这篇文章主要介绍了JUC系列学习工具类CountDownLatch详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可任意参考一下
前言:
项目中我们经常会遇到有时候需要等待其他线程完成任务后,主线程才能执行其他任务,那么我们将如何实现呢?
Join 解决方案
加入的工作原理是,检查线是否存活,如果存活则让当前线程永远等等,直到线线程终止,线程的notifyAll才会被调用。
具体实现
公共类JoinAThread扩展线程
{
@覆盖
公共无效运行(){
系统。出去。println(线程。当前线程().getName()
' 线程开始');
尝试{
线程。睡眠(100);
} catch (InterruptedException e) {
e。printstacktrace();
}
系统。出去。println(线程。当前线程().getName()
' 线程执行完毕');
}
}
公共类JoinBThread扩展线程
{
@覆盖
公共无效运行(){
系统。出去。println(线程。当前线程().getName()
' 线程开始');
尝试{
线程。睡眠(100);
} catch (InterruptedException e) {
e。printstacktrace();
}
系统。出去。println(线程。当前线程().getName()
' 线程执行完毕');
}
}
公共类联合测试
{
公共静态void main(String[] args)引发中断异常
{
JoinAThread joinA=new JoinAThread();
螺纹螺纹A=新线程(joinA,线程a’);
JoinBThread joinB=new JoinBThread();
螺纹螺纹B=新线程(joinB,线程b’);
threada。start();
threadb。start();
threada。join();
threadb。join();
System.out.println('子线程执行完成了,主线程Thread.currentThread().getName()'开始执行了');
}
}
执行结果
从结果中,我们可以看出只有子线程执行完成了,主线程才开始执行加入。的实现我们需要每个线程进行加入,如果存在多个线程,那么写起来会比较的繁琐,那么又没更新优化的方案了,答案是JUC下面的工具类CountDownLatch,也能完成同样的功能。
CountDownLatch 解决方案
具体实现
公共类CountDownLatchTest
{
私有静态记录器记录器=记录器工厂。获取记录器(countdownlatchtest。类);
公共静态void main(String[] args)引发中断异常
{
执行者服务exec=执行者。newcachedthreadpool();
final CountDownLatch CountDownLatch=new CountDownLatch(10);
for(int I=1;i=10i ){
exec.execute(() - {
尝试{
invokeServiec();
} catch(中断异常e)
{
logger.info('invoce服务错误,e);
}
最后
{
//计数器减一
countdownlatch。倒计时();
}
});
}
countdownlatch。await();
logger.info('所有的子线程执行完成,主线程Thread.currentThread().getName()'开始执行');
}
私有静态void invokeServiec()引发中断异常
{
伐木工。信息(线程。当前线程().getName()',开始执行任务');
线程。睡眠(300);
}
}
说明:CountDownLatch中有两个方法一个是等待()方法,调用这个方法的线程会被阻塞,另外一个是倒计时()方法,调用此方法会使计数器减一,当计数器的值为0时,调用等待()方法被阻塞的线程才会被唤醒。
执行结果:
原理说明
CountDownLatch是一个计数器锁存器,可以完成类似于阻塞当前线程的功能,即一个线程或多个线程等待,直到其他线程执行的操作完成。
基本原理
CountDownLatch
CountDownLatch在内部定义计数器和队列。在计数器递减到0之前,阻塞队列中的线程被挂起。当计数器递减到0时,阻塞队列中的所有线程都将被唤醒。计数器是一个符号,它可以指示一个任务、一个线程或一个倒计时定时器。
常用的方法
倒计时:用于将计数器减一,通常由执行任务的线程调用。await:用户线程处于等待状态,通常由主线程调用。
countDown
countDown实现方法如下:
说明:sync是AQS的队列,它调用AQS的releaseShared方法。其具体实现如下:
而releaseShared调用为CountDownLatch中的内部类sync中的tryReleaseShared方法,具体实现如下:
tryreaseshared(int)方法是将state属性减一的代码。CAS递减以保证原子性,会比较状态是否为C,如果是,则设置为nextc(自减一),如果不是C,则另一个线程已经在getState()方法和compareAndSetState()方法调用之间设置了状态,当前线程还没有成功设置state属性的值,则进入下一个循环,以此类推,直到成功设置state属性的值,即countDown()方法调用成功。
而doreleasshared方法调用AbstractQueuedSynchronizer(简称AQS)的doreleasshared方法,
注意:首先判断头节点不为空,也不是尾节点,说明等待队列中有等待唤醒的线程。这里需要注意的是,在等待队列中,等待线程不是存储在head节点中,而是一个空的node对象。真正的等待线程是从头节点的下一个节点开始存储的,所以会有一个头节点是否等于尾节点的判断。判断等待队列中有等待线程后,会清除头节点的状态信息,调用unparkSuccessor(Node)方法唤醒头节点的下一个节点,使其继续执行。它是以下unparkSuccessor(Node)方法的具体实现:
可以看到,unparkSuccessor(Node)方法的作用是唤醒离传入节点最近的等待线程,使其继续执行。
await
await方法实现如下:
await()方法调用了Sync对象的方法acquireSharedInterruptibly(int)方法,该方法的具体实现如下:
在doacquiresharedinterruptily(int)方法中,首先,使用当前线程创建一个共享模式节点。然后在for循环中,判断当前线程是否获得了执行权限,如果是(r=0判断),则将当前节点设置为头节点,唤醒共享模式的后续节点;否则,调用ShouldParkAfterFileDacquire(node,node)和parkAndCheckInterrupt()方法将当前线程置于“保持”状态。‘hold’状态由操作系统进行,可以避免线程的死循环和执行权的缺失,造成资源的浪费。在这里,线程处于等待状态,这意味着当线程被阻塞时,它被阻塞在这个位置。当多个线程调用await()方法并进入等待状态时,这些线程都会在这里等待。
总结
本文详细解释了JUC的工具类CountDownLatch。如果您有任何问题,请随时反馈。
以上就是本文关于JUC系列学习工具类CountDownLatch的详细讲解。有关JUC工具类CountDownLatch的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。