JUC同步工具CountDownLatch
2022-12-12 10:06 杭伟 阅读(19) 评论(0) 编辑 收藏 举报CountDownLatch:允许一条或多条线程等待其它线程中的一组操作完成后再继续执行。
在探究CountDownLatch之前,我们知道Thread的join也有类似功能,先看thread的join方法:
1 public static void main(String[] args) throws InterruptedException{ 2 Thread t1 = new Thread(new Runnable() { 3 @Override 4 public void run() { 5 System.out.println("i am t1"); 6 } 7 }); 8 Thread t2 = new Thread(new Runnable() { 9 @Override 10 public void run() { 11 try { 12 t1.join(); 13 } 14 catch (InterruptedException e){} 15 System.out.println("i am t2"); 16 } 17 }); 18 Thread t3 = new Thread(new Runnable() { 19 @Override 20 public void run() { 21 try { 22 t2.join(); 23 } 24 catch (InterruptedException e){} 25 System.out.println("i am t3"); 26 } 27 }); 28 t1.start(); 29 t2.start(); 30 t3.start(); 31 }
Thread join方法原理:
源码中,可以看到join调用了Object的wait方法,是一个无限等待。
疑问:既然这里有wait,那notify去哪了?
原来在jvm源码中有这样一句:
1 // 位于/hotspot/src/share/vm/runtime/thread.cpp中 2 void JavaThread::exit(bool destroy_vm, ExitType exit_type) { 3 // ... 4 5 // Notify waiters on thread object. This has to be done after exit() is called 6 // on the thread (if the thread is the last thread in a daemon ThreadGroup the 7 // group should have the destroyed bit set before waiters are notified). 8 // 看这里 9 ensure_join(this); 10 11 // ... 12 } 13 14 15 static void ensure_join(JavaThread* thread) { 16 // We do not need to grap the Threads_lock, since we are operating on ourself. 17 Handle threadObj(thread, thread->threadObj()); 18 assert(threadObj.not_null(), "java thread object must exist"); 19 ObjectLocker lock(threadObj, thread); 20 // Ignore pending exception (ThreadDeath), since we are exiting anyway 21 thread->clear_pending_exception(); 22 // Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED. 23 java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED); 24 // Clear the native thread instance - this makes isAlive return false and allows the join() 25 // to complete once we've done the notify_all below 26 java_lang_Thread::set_thread(threadObj(), NULL); 27 28 // 看这里 29 lock.notify_all(thread); 30 31 // Ignore pending exception (ThreadDeath), since we are exiting anyway 32 thread->clear_pending_exception(); 33 }
回到CountDownLatch:
使用:
1 public static void main(String[] args) throws InterruptedException{ 2 CountDownLatch c2 = new CountDownLatch(1);//t2使用 3 CountDownLatch c3 = new CountDownLatch(1);//t3使用 4 Thread t1 = new Thread(new Runnable() { 5 @Override 6 public void run() { 7 System.out.println("i am t1"); 8 c2.countDown(); 9 } 10 }); 11 12 Thread t2 = new Thread(new Runnable() { 13 @Override 14 public void run() { 15 try { 16 c2.await(); 17 } 18 catch (InterruptedException e){} 19 System.out.println("i am t2"); 20 c3.countDown(); 21 } 22 }); 23 Thread t3 = new Thread(new Runnable() { 24 @Override 25 public void run() { 26 try { 27 c3.await(); 28 } 29 catch (InterruptedException e){} 30 System.out.println("i am t3"); 31 } 32 }); 33 t1.start(); 34 t2.start(); 35 t3.start(); 36 }
CountDownLatch原理:
利用AQS,主线程(需要等待其它线程的线程)进入AQS队列中等待,前置线程通过State获取锁并执行任务,当State=0时即表示任务全部执行完毕。主线程唤醒。
await()方法 ==》
主线程入队等待:LockSupport.park()
countDown方法 ==》分成两步:
1,前置线程执行完释放锁,State-1;
2,一旦State=0,唤醒主线程。
可以看到,CountDownLatch更加灵活,Join方法必须等待前置线程执行完毕才能开始执行下一线程,中间过程无法控制;
而CountDownLatch的countDown方法可以自由的对任务片段进行控制。
作者:hangwei
出处:http://www.cnblogs.com/hangwei/
关于作者:专注于开源平台,分布式系统的架构设计与开发、数据库性能调优等工作。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
如果您觉得文章对您有帮助,可以点击文章右下角“推荐”一下。您的鼓励是作者坚持原创和持续写作的最大动力!