JUC——JUC强大辅助类讲解
文章目录
- 1:JUC是什么
- 2:倒计数器——CountDownLatchDemo
- 3:循环栅栏——CyclicBarrier
- 4:允许多个线程同时访问——Semaphore(信号量)
1:JUC是什么
JUC全名java.util.concurrent是一种在并发编程中使用的工具类
JUC主要是三大包构成:并发包,并发原子包,并发lock包
如下介绍的三种辅助类都是在java.util.concurrent包下
2:倒计数器——CountDownLatchDemo
CountDownLatch是一个非常实用的多线程控制工具类。"Count Down”在英文中意为倒计数,Latch 意为门闩的意思,这里简单地称之为倒计数器。在这里,门闩的含义是把门锁起来,不让里面的线程跑出来。因此,这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计数结束,再开始执行。
CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行
下面这个简单的实例,演示CountDownLatch用法
题目:班长(主线程)监督六个同学上自习,假设第一个同学八点就走了,第二个九点就走了。。要求六个同学走完了,班长(主线程)才可以走
代码演示
public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {3 CountDownLatch countDownLatch=new CountDownLatch(6);for (int i=0;i<6;i++){new Thread(()->{System.out.println(Thread.currentThread().getName()+"离开教室");7 countDownLatch.countDown();},String.valueOf(i)).start();}10 countDownLatch.await();System.out.println(Thread.currentThread().getName()+"班长关门走人");}}
上述代码第3行生成一个CountDownLatch 实例,计数数量为6, 这表示需要6个线程完成任务后等待在CountDownLatch上的线程(主线程)才 能继续执行。代码第7行使用了CountDownL atch.countdown()方法,也就是通知CountDownLatch, 一个线程已经完成了任务倒计数器减1。第10行使用CountDownLatch.awai()方法,要求主线程等待所有检查任务全部完成,待6个任务全部完成后,主线程才能继续执行。
主线程在CountDownLatch等待,当所有任务全部完成以后,主线程才可以继续执行
如上例子类似的一个 典型的场景就是火箭发射。在火箭发射前,为了保证万无一失,往往还要对各项设备、仪器进行检查。只有等所有检查都完成后,引擎才能点火。这种场景就非常适合使用CountDownLatch。它可以使点火线程等待所有检查线程全部完工后再执行。
3:循环栅栏——CyclicBarrier
CyclicBarrier是另外一种多线程并发控制工具。和CountDownLatch非常类似,它也可以实现线程间的计数等待,但它的功能比CountDownLatch更加复杂且强大。
CylicBarrier可以理解为循环栅栏,栅栏就是一种障碍物, 比如,通常在别墅的周围就可以围上一圈栅栏,阻止闲杂人等入内。(用来阻止线程继续执行,要求线程在栅栏外等待)前面Cyelic意为循环,也就是说这个计数器可以反复使用。比如,我们将计数器设置为10,那么凑齐第一批10个线程后,计数器就会归零,接着凑齐下一批10个线程,这就是循环栅栏内在的含义。
CyclicBarrier 比CountDownLatch略微强大些, 它可以接收一个参数作为barrierAction.所谓barrierAction就是当计数器一次计数完成后, 系统会执行的动作。如下构造函数,其中,parties表示计数总数,也就是参与的线程总数。
CyclicBarrier(int parties, Runnable barrierAction)
//创建一个新的CyclicBarrier,当给定数量的参与方(线程)正在等待它时,
//它将触发,当触发barrier时,它将执行给定的barrier操作,
//该操作由进入barrier的最后一个线程执行。
CyclicBarrier的使用场景也很丰富。比如,召唤七龙珠,只有集齐了七颗龙珠才可以召唤神龙。
下面的代码示例使用CyclicBarrier演示召唤七龙珠,召唤神龙的场景
public class CyclicBarrierDemo {public static void main(String[] args) {3 CyclicBarrier cyclicBarrier= new CyclicBarrier(7,()-> System.out.println("**召唤神龙"));for (int i=0;i<7;i++){final int tempt=i;
6 new Thread(()->{System.out.println(Thread.currentThread().getName()+"收集到第:"+tempt+"颗龙珠");try {9 cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}},String.valueOf(i)).start();}}
}
3收集到第:3颗龙珠
0收集到第:0颗龙珠
1收集到第:1颗龙珠
2收集到第:2颗龙珠
4收集到第:4颗龙珠
5收集到第:5颗龙珠
6收集到第:6颗龙珠
**召唤神龙
上述代码第3行创建了CyliBrrier 实例,并将计数器设置为7,要求在计数器达到指标时,执行第3行的barrierAction。每一个收集龙珠的线程都会执行第6行定义的run()方法。在第9行,每一个收集龙珠的线程都会等待,直到所有的收集龙珠的线程都集合完毕。集合完毕意味着CyelicBarrier 的一次计 数完成.。一旦任务全部完成,第3行定义的barrierAction就会被调用,打印相关信息。
在第9行后再加一段代码
10 dowork();// private static void dowork() { System.out.println("龙珠准备好了"); }
11 cyclicBarrier.await();
执行效果
//篇幅有限
4收集到第:4颗龙珠
**召唤神龙
龙珠准备好了
//篇幅有限
**召唤神龙
当再次调用cyclicBarrier.await()方法时, 会进行下次计数。第10行模拟了龙珠准备好了的任务。当一个龙珠准备好了,他就会要求CyelicBarrier开始下一次计数,这次计数主要目的是监控是否所有的龙珠都准备好了。一旦所有的龙珠都准备好了,第3行定义的barrierAction就会被调用,打印相关信息。
CyelicBarrier.await()方法可能会抛出两个异常。一个是InteruptedException, 也就是在等待过程中,线程被中断,应该说这是一个非常通用的异常。 大部分迫使线程等待的方法都可能会抛出这个异常,使得线程在等待时依然可以响应外部紧急事件。另外一个异常则是CyelicBarrier 特有的BrokenBarrierException。一旦遇到这个异常,则表示当前的CyclicBarrier已经破损了,可能系统已经没有办法等待所有线程到齐了。如果继续等待,可能就是徒劳无功,赶快回家吧。
4:允许多个线程同时访问——Semaphore(信号量)
信号量为多线程协作提供了更为强大的控制方法, 广义上说,信号量是对锁的扩展。无论是内部锁synchronized,还是重入锁RentantLtock,一次都只允许一个线程访问一个资源。可信号量却可以指定多个线程,同时访问某一个资源。 信号量主要提供了以下构造函数:
public Semaphore(int permits)
public Semaphore(int pemits, boolean fair)//第二个参数可以指定是否公平
在构造信号量对象时,必须要指定信号量的准入数,即同时能申请多少个许可。当每个线程每次只申请一个许可时,这就相当于指定了同时有多少个线程可以访问某一个资源。信号量的主要逻辑方法有:
public void acquire()
public void acquireUninterruptibly()
public boolean tryAcquire()
public boolean tryAcquire (long timeout, TimeUnit unit)
public void release ()
acquire()方法尝试获得一个准入的许可。若无法获得,则线程会等待,直到有线程释放个许可或者当前线程被中断。acquireUninterruptibly()方法和acquire0方法类似,但是不响应中断。tryAcquire()方法尝试获得一个许可, 如果成功则返回true, 失败则返回false, 它不会进行等待,只会立即返回。release()方法用于在线程访问资源结束后释放一个许可,以使其他等待许可的线程可以进行资源访问。
下面用一个简单的争车位例子来介绍Semaphore使用
争车位,以前都是多线程去抢一个资源,如果现在是多对多呢?比如现在六个人去停三个车位,就是六个人去争三个车位,怎么抢呢?言下之意就是信号量可以控制多线程的并发数
代码演示
public class SemaphoreDemo {public static void main(String[] args) {3 Semaphore semaphore = new Semaphore(3);//模拟资源类,3个停车位for (int i=0;i<6;i++){new Thread(()->{6 try {semaphore.acquire();System.out.println(Thread.currentThread().getName()+"获取到了停车位");Thread.sleep(3000);//在停车位停3秒离开System.out.println(Thread.currentThread().getName()+"离开了停车位");} catch (InterruptedException e) {e.printStackTrace();}finally {14 semaphore.release();15 }},String.valueOf(i)).start();}}
}
1获取到了停车位
0获取到了停车位
3获取到了停车位
0离开了停车位
1离开了停车位
3离开了停车位
4获取到了停车位
5获取到了停车位
2获取到了停车位
4离开了停车位
5离开了停车位
2离开了停车位
第3行代码声明了一个包含3个许可的信号量。这就意味着同时可以有3个线程进入代码段第6-15行。第6-15行为临界区管理代码,程序会限制执行这段代码的线程数。申请信号量使用acquire()方法操作,在离开时,务必使用release()方法释放信号量(代码第14行)。这就和释放锁是一个道理。如果不幸发生了信号量的泄露(申请了但没有释放),那么可以进入临界区的线程数量就会越来越少,直到所有的线程均不可访问。在本例中,同时开启6个线程。观察这段程序的输出,你就会发现系统以3个线程一组为单位, 依次输出获取到了停车位,离开了停车位。
如上代码如果注释掉了第14行,出现如下结果。说明发生了信号量的泄露(申请了但没有释放),那么可以进入临界区的线程数量就会越来越少,并且程序运行不会停止,线程一直等待
1获取到了停车位
2获取到了停车位
0获取到了停车位
2离开了停车位
1离开了停车位
0离开了停车位
如上代码如过把第3行的 Semaphore semaphore = new Semaphore(3);换成
Semaphore semaphore = new Semaphore(1);就等价于synchronized。
多线程抢占资源,如果我们要求抢到的资源停留30秒中,我们就可以使用信号量
JUC——JUC强大辅助类讲解相关推荐
- Day127.JUC:线程间通信(Conditon)、并发容器类(CopyOnWrite)、JUC强大辅助类、Callable
. 目录 一.线程间通信 线程间通信改造成Lock版 Condition 定制化调用通信 Condition 二.并发容器类 (解决集合安全问题) CopyOnWrite 写时拷贝技术 三.JUC ...
- JUC基础(一): 什么是JUC(JUC概述)
什么是JUC JUC简介 在Java中,线程部分是一个重点,本篇文章说的JUC也是关于线程的. JUC就是java.util.concurrent工具包的简称. 这是一个处理线程的工具包, JDK1. ...
- JUC阻塞队列BlockingQueue讲解
概述 阻塞队列有两个特性: 阻塞:当队列为空时,会阻塞队列弹出操作,直到队列不为空.当队列满了时,会阻塞入队操作,直到队列不满. 队列:FIFO,先进先出. 接口:java.util.concurre ...
- Java并发包JUC的Lock锁讲解
概述 Java有两种锁,一种是使用关键字Synchronized对方法或者代码块进行加锁,一种是使用接口Lock(实际上其实现类)进行上锁和解锁. 区别: Synchronized是java的一个关键 ...
- JUC介绍--常用辅助类(CountDownLatch CyclicBarrier Semaphore)
CountDownLatch减法计数器 每次有线程调用countDownLatch.countDown()数量就-1 数量减到0时,countDownLatch.await()会被唤醒,继续向下执行 ...
- 【Java】高并发-JUC:JUC中的Condition对象
1.Condition使用简介 从整体上来看Object的wait和notify/notify是与对象监视器配合完成线程间的等待/通知机制,而Condition与Lock配合完成等待通知机制,前者是j ...
- 浅谈Java锁,与JUC的常用类,集合安全类,常用辅助类,读写锁,阻塞队列,线程池,ForkJoin,volatile,单例模式不安全,CAS,各种锁
浅谈JUC的常用类 JUC就是java.util.concurrent-包下的类 回顾多线程 Java默认有几个线程? 2 个 mian.GC Java 真的可以开启线程吗? 开不了,点击源码得知:本 ...
- JUC高并发编程从入门到精通(全)
目录 前言 1. Lock接口 1.1 复习synchronized 1.2 Lock接口 1.3 Lock方法 1.4 两者差异 2. 线程间通信 2.1 synchronized案例 2.2 Lo ...
- JUC笔记之尚硅谷周阳老师思维导图整理
文章目录 1. JUC 是什么 2. Lock 接口 3. Lambda表达式复习--详情请看 on java 8 4. 线程间通信 5. 线程间定制化调用通信 6.NotSafeDemo 7.多线程 ...
最新文章
- 机器学习_周志华_问题汇总_第2周
- 实现不可变类如何禁止子类化?
- 二、Windows下TortoiseGit的安装与配置
- mysql可以打开dbt么_dbt 基本试用
- Redis Linux 安装运行实战全记录
- harbor pull 失败
- nao机器人行走速度_震撼!寒冬腊月里惊现多台历途外墙清洗机器人
- 为什么python打不开_python文件打不开如何解决
- c调用python第三方库_Python使用ctypes模块调用DLL函数之C语言数组与numpy数组传递...
- 任达华遇袭是效仿“宏颜获水”事件?百度回应:严惩肇事者 以儆效尤
- Atitit 获取剪贴板内容
- 随手写了个android应用
- Robotium 常用方法
- 被中国家长摧残的十种优秀儿童品质(转)
- Mac无法开机?别着急看这里
- java项目开发实践经验每日总结(2014/2/22)
- 手机百度浏览器ua标识在哪里_浏览器标识(ua)的那些事
- 时序预测 | MATLAB实现贝叶斯优化CNN-LSTM时间序列预测(股票价格预测)
- MySQL各数据类型总结
- 高职高专院校的消防工作和措施
热门文章
- 影响项目进度的因素有哪些?如何跟踪项目计划?
- 动作游戏Demo(一)换装系统
- 数字摘要和数字签名等概念
- 2021年高压电工报名考试及高压电工考试试卷
- 单片机c语言篮球比分_基于单片机的篮球记分器设计报告
- jstat和jmap打印堆栈排查内存泄漏
- failed to allocate 2.00G (2147483648 bytes) from device: CUDA_ERROR_OUT_OF_MEMORY: out of memory
- 模拟部署FTP服务器并提供文件的上传及下载
- 自动驾驶—自动泊车之AVM环视系统算法框架
- 如何10分钟建立一个网站