JUC系列(五) 读写锁与阻塞队列

news2024/11/25 1:05:24

📣 📣 📣 📢📢📢
☀️☀️你好啊!小伙伴,我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。
📒 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️,擅长使用Java技术开发web项目和工具
📒 文章内容丰富:覆盖大部分java必学技术栈,前端,计算机基础,容器等方面的文章
📒 如果你也对Java感兴趣,关注小冷吧,一起探索Java技术的生态与进步,一起讨论Java技术的使用与学习
✏️高质量技术专栏专栏链接: 微服务数据结构netty,单点登录,SSMSpringCloudAlibaba
😝公众号😝想全栈的小冷,分享一些技术上的文章,以及解决问题的经验
当前专栏JUC系列

读写锁

Synchronized存在一个性能问题就是不同读取之间互斥,我们想要实现的最好效果是可以做到读和读互不影响,写的时候只有一个线程能写

解决方案 : ReadWriteLock。

案例代码

package rwLock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @projectName: JUC
 * @package: rwLock
 * @className: rwLockDemo
 * @author: 冷环渊 doomwatcher
 * @description: TODO
 * @date: 2022/3/2 16:29
 * @version: 1.0
 */
public class rwLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.put(temp + "", temp + "");

            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.get(temp + "");
            }, String.valueOf(i)).start();
        }
    }
}

/**
 * 自定义缓存类
 * 加锁
 * */
class MyCache {
    //存放数据的集合
    private volatile Map<String, Object> map = new HashMap<>();

    //    存 写
    public void put(String key, Object value) {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完毕");
    }
    //    取 读
    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + "读取" + key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() + "读取" + "");
    }
}

image-20220302170621703

可以看到这并不是我们想要的效果,这个时候我们需要加锁

ReadWriteLock读写锁 分别有

readLock()读锁

writeLock()写锁

使用方式除了相比lock细化的一些其他没有变化

读写锁代码实例

思路理解 :

独占锁(写锁)

共享锁(读锁)

public class rwLockDemo {
    public static void main(String[] args) {
        //MyCache myCache = new MyCache();
        MyCacheLock myCache = new MyCacheLock();
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.put(temp + "", temp + "");
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(() -> {
                myCache.get(temp + "");
            }, String.valueOf(i)).start();
        }
    }
}
class MyCacheLock {
    //存放数据的集合
    private volatile Map<String, Object> map = new HashMap<>();

    //读写锁的区别, 更加细粒度的控制
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //    存 写
    public void put(String key, Object value) {
        //加入写锁
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放写锁
            readWriteLock.writeLock().unlock();
        }
    }

    //    取 读
    public void get(String key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取" + "");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

输出效果就达到了,先写且只有一个写,之后随意读

image-20220302182538999

阻塞队列

阻塞队列简介

什么是阻塞队列,我们要分开来理解

阻塞: 等待前面的走了才能加入新的

队列: 先进来的,先出去

image-20220302183347089

阻塞队列 在jdk文档中的 解释

image-20220302183907308

队列接口

我们学习的BlockingQueue也是实现类之一

什么时候我们会使用 阻塞队列

多线程 , 线程池 用的相对的多一点

image-20220302184326096

队列的类关系图

image-20220302184516163

阻塞队列相对的四组api

  1. 抛出异常api

        /** 会抛出异常的
         * java.lang.IllegalStateException: Queue full 会抛出队列已经满了的异常
         * java.util.NoSuchElementException  过多移除异常
         * */
        public static void test1() {
            ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
            System.out.println("===============多过加入================");
            System.out.println(blockingQueue.add("a"));
            System.out.println(blockingQueue.add("b"));
            System.out.println(blockingQueue.add("c"));
    
                此时的队列长度为 3 如果我们此时加入 第四个会怎么样,抛出队列已经满了的异常
            //System.out.println(blockingQueue.add("b"));
            System.out.println("===============过多移除================");
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
            System.out.println(blockingQueue.remove());
        }
    
  2. 不会抛出异常api

    public static void test2() {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println("===============多过加入================");
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        //返回false
        System.out.println(blockingQueue.offer("d"));
        System.out.println("===============过多移除================");
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        //返回null
        System.out.println(blockingQueue.poll());
    
    }
    
  3. 阻塞等待 api

    /* 一直等待 阻塞
     * */
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        //blockingQueue.put 队列没有位置了 一支阻塞
        //blockingQueue.put("d");
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        //m没有这个元素一直等待
        System.out.println(blockingQueue.take());
    }
    
  4. 超时等待 api

    /*等待
    等待超时*/
    public static void test4() throws InterruptedException {
        //队列的大小
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        blockingQueue.offer("a");
        blockingQueue.offer("b");
        blockingQueue.offer("c");
        //等待,如果设置时间还没有空位置。否则结束
        blockingQueue.offer("d", 2, TimeUnit.SECONDS);
        System.out.println("======================");
        blockingQueue.poll();
        blockingQueue.poll();
        blockingQueue.poll();
        //等待,如果设置时间还没有找到。否则结束
        blockingQueue.poll(2, TimeUnit.SECONDS);
    
    }
    
方式抛出异常有返回值阻塞等待超时等待
添加操作addofferput()offer()
移除操作removepolltake()poll()
判断队列首元素elementpeek

同步队列

特性

同步队列,SynchronusQueue 同步队列 和其他的 BlockingQueue不一样 SynchronusQueue不存储元素

put了 一个元素 必须先从里面拿出来,否则是不能再put进去值

代码实例

public class synchronusQueueDemo {
    public static void main(String[] args) {
        BlockingQueue<String> blockingQueue = new SynchronousQueue<>();
        new Thread(() -> {

            try {
                System.out.println(Thread.currentThread().getName() + "put 1");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "put 3");
                blockingQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();
        new Thread(() -> {

            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T2").start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/48753.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt第二十六章:Nuitka打包教程

Nuitka环境安装 ①下载gcc文件。提取码&#xff1a;8888百度网盘 请输入提取码 ②解压nuitka1.0.6版本&#xff0c;我们解压64位的。 ③设置环境变量 ④检测一下 gcc.exe --version 安装nuitka pip install nuitka pip install ordered-set 防止环境变量不生效&#xff0c;…

【Redis】Redis介绍

文章目录1.NoSQL数据库1.1NoSQL适用场景1.2常用的NoSQL1.3Redis介绍1.4Redis的使用场景1.5Redis默认按照目录1.6Redis的启动1.7Redis是单线程多路IO复用技术1.NoSQL数据库 NoSQL(NoSQL Not Only SQL )&#xff0c;意即“不仅仅是SQL”&#xff0c;泛指非关系型的数据库。 NoS…

学生HTML个人网页作业作品 (服装商城HTML+CSS)

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 在线商城购物 | 水果商城 | 商城系统建设 | 多平台移动商城 | H5微商城购物商城项目 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&a…

RK3588平台开发系列讲解(Pinctrl篇)Pinctrl设备树介绍

平台内核版本安卓版本RK3588Linux 5.10Android12🚀返回专栏总目录 文章目录 一、 DTS介绍二、新建pinctrl三、引用pinctrl沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍pinctrl设备树的使用方法。 一、 DTS介绍 RK芯片的设备树⼀般把pinctrl节点放在soc…

元宇宙数字藏品,打造数字经济产业,实现全新业态升级

《中华人民共和国国民经济和社会发展第十四个五年规划和2035年远景目标纲要》提出以数字化转型整体驱动生产方式、生活方式和治理方式变革&#xff0c;催生新产业新业态新模式&#xff0c;壮大经济发展新引擎&#xff0c;将“虚拟现实和增强现实”列入了数字经济重点产业。 而自…

GAN生成漫画脸

最近对对抗生成网络GAN比较感兴趣&#xff0c;相关知识点文章还在编辑中&#xff0c;以下这个是一个练手的小项目~ (在原模型上做了&#xff0c;为了减少计算量让其好训练一些。) 一、导入工具包 import tensorflow as tf from tensorflow.keras import layersimport numpy a…

tinymce富文本编辑器做评论区

今天分享一下tinymce富文本编辑器做评论区的全过程。 文章目录一、介绍1.最终效果2.功能介绍3.主要项目包版本介绍&#xff1a;二、每个功能的实现1.自定义toolbar的功能区①对应的样式以及意义②对应的代码实现【忽略了一切非实现该功能的代码】2.展示、收起评论区①对应的样式…

ctf工具之:mitmproxy实践测试

1、安装居然使用的pip pip install mitmproxy 导入证书&#xff0c;密码为空 2、启用mitmweb pause 直接可以查看方式 搜索里输入login 对于http协议 直接看到了密码原文 3、后台日志方式 录入和回放 mitmdump -w baidu.txt pause 录制结束 mitmdump -nC baidu.txt paus…

如何设计可扩展架构

架构设计复杂度模型 业务复杂度和质量复杂度是正交的 业务复杂度 业务固有的复杂度&#xff0c;主要体现为难以理解、难以扩展&#xff0c;例如服务数量多、业务流程长、业务之间关系复杂 质量复杂度 高性能、高可用、成本、安全等质量属性的要求 架构复杂度应对之道 复杂…

MySQL备份与恢复

目录 一.数据备份的重要性 二.数据库备份的分类 2.1 物理备份 2.2 逻辑备份 2.3 完全备份&#xff08;只适合第一次&#xff09; 三.常见的备份方法 四.MySQL完全备份 4.1 MySQL完全备份优缺点 4.2 数据库完全备份分类 4.2.1 物理冷备份与恢复 五.完全备份 5.1 MySQ…

YOLO家族再度升级——阿里达摩院DAMO-YOLO重磅来袭

最近看到阿里达摩院发表了他们的最新研究成果&#xff0c;在YOLO系列上推出的新的模型DAMO-YOLO&#xff0c;还没有来得及去仔细了解一下&#xff0c;这里只是简单介绍下&#xff0c;后面有时间的话再详细研究下。 官方项目在这里&#xff0c;首页截图如下所示&#xff1a; 目…

ASEMI整流桥UD4KB100,UD4KB100体积,UD4KB100大小

编辑-Z ASEMI整流桥UD4KB100参数&#xff1a; 型号&#xff1a;UD4KB100 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;1000V 最大平均正向整流输出电流&#xff08;IF&#xff09;&#xff1a;4A 峰值正向浪涌电流&#xff08;IFSM&#xff09;&#xf…

堆(C语言实现)

文章目录&#xff1a;1.堆的概念2.堆的性质3.堆的结构4.接口实现4.1初始化堆4.2销毁堆4.3打印堆内元素4.4向上调整4.5向堆中插入数据4.6向下调整4.7删除堆顶元素4.8查看堆顶元素4.9统计堆内数据个数4.10判断堆是否为空4.11堆的构建1.堆的概念 如果有一个关键码的集合&#xff0…

【Redis】缓存更新策略

1. 缓存更新策略综述 内存淘汰 不用自己维护&#xff0c;利用 Redis 自己的内存淘汰机制 &#xff08;内存不足时&#xff0c;触发策略&#xff0c;默认开启&#xff0c;可自己配置&#xff09;&#xff0c;其可在一定程度上保持数据一致性 超时剔除 给数据添加 TTL&#x…

【电力运维】浅谈电力通信与泛在电力物联网技术的应用与发展

摘要&#xff1a;随着我国社会经济的快速发展&#xff0c;我国科技实力得到了巨大的提升&#xff0c;当前互联网通信技术在社会中得到了广泛的应用。随着电力通信技术的快速发展与更新&#xff0c;泛在电力物联网建设成为电力通讯发展的重要方向。本文已泛在电力物联网系统为核…

Docker使用

xshell和xftp软件下载 链接&#xff1a;https://pan.baidu.com/s/1G7DIw14UvOmTwU9SwtYILg 提取码&#xff1a;he18 --来自百度网盘超级会员V6的分享 docker相关资料&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1VcxvuJvBIKNKnUUHPlM3MA 提取码&#xff1a;6w5e …

一些常见的项目管理 KPI

本文将介绍一些常见的项目管理kpi&#xff0c;让大家更深刻的了解其作用及所存在的问题。 一、关键绩效指标的作用 在 GPS 和其他现代导航方法出现之前&#xff0c;水手和探险家们只能通过星星找到正确的方向。特别是在北半球&#xff0c;他们利用北极星找出真正的北方方位。…

[附源码]SSM计算机毕业设计医学季节性疾病筛查系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Mysql高频面试题(一)

文章目录1. Mysql如何实现的索引机制&#xff1f;2. InnoDB索引与MyISAM索引实现的区别是什么&#xff1f;3. 一个表中如果没有创建索引&#xff0c;那么还会创建B树吗&#xff1f;4. B树索引实现原理&#xff08;数据结构&#xff09;5. 聚簇索引与非聚簇索引的B树实现有什么区…

Vector源码分析

Vector源码分析 1 Vector基本介绍与类图 Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的: Vector 是同步访问的。Vector 包含了许多传统的方法,这些方法不属于集合框架。Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的…