Java的多线程协调工具CountDownLatch,Semaphore,CyclicBarrier,ReadWriteLock都是在多线程代码中使用比较多的工具类之一。掌握及理解这几个类的实现,对解决和理解多线程中复杂的业务情况有很重要的做用。绝不夸张的说,这几个类,是等同于解决多线程问的java.util包,实在有必要添加到程序员的工具箱里面。java
这次文章,将分几篇总结及解读一下这些工具类的具体用法和范例,最后,但愿能够再深刻一点去理解这几个多线程工具的实现。程序员
CountDownLatch是一个经常使用的多线程协调工具:主要为协调一个或多个线程完成后,主线程进行某个操做的功能。shell
Latch原指门闩,CountDownLatch译为倒数锁却是不太过度。能够理解为:使用主线程初始化一个有N个子锁的锁,任务开始的时,分配给N个线程每一个线程持有一把钥匙,每一个线程到某个状态后(通常为完成),可使用线程持有的钥匙打开主线程持有的锁,直至全部N个锁都被打开,主线程才能够继续其余任务。多线程
从API上看咱们能够关注下面几个CountDownLatch提供了几个接口:函数
构造方法十分简单,注入一个int,初始化倒数锁的大小。工具
等待全部锁被解开,该函数还有一个带等待时长及等待时间单位的重写await(long time, TimeUnit unit),用于避免过分的等待形成的死锁。测试
解锁方法,解开一个锁,知道持有的锁数量为0,则接触await的状态。this
获取当前的剩余的锁的数量。线程
在范例中,咱们简单的使用一个主线程,发起若干个子线程,让子线程进行休眠的例子做为测试倒数,让各个子线程导数完通知解锁,主线程会被在全部子线程完成解锁后通知全部任务完成。code
import java.util.concurrent.CountDownLatch; import java.util.logging.Logger; public class App { static Logger log = Logger.getAnonymousLogger(); public static void main(String[] args) { for (int index = 0; index < 10; index++) { new Thread(new SubThread(index, index)).start(); } // 全部的线程都完成了 log.info("all thread finished"); } }
import java.util.concurrent.CountDownLatch; import java.util.logging.Logger; public class SubThread implements Runnable { private int id; private int waitSecond; static Logger log = Logger.getAnonymousLogger(); public SubThread(int id, int waitSecond) { this.id = id; // 秒数*1000毫秒 = 实际等待毫秒数 this.waitSecond = waitSecond * 1000; } public void run() { try { log.info("Thread " + id + " started."); // 让Thread再飞一下子 Thread.sleep(waitSecond); log.info("Thread " + id + " end."); // 通知完成 } catch (InterruptedException e) { log.config("error"); } } }
能够从结果中看到,全部的线程启动后,主线程就会马上退出,子线程会在完成各自的任务后再退出。
Aug 09, 2018 6:43:22 PM online.tangbk.demo.thead.SubThread run INFO: Thread 3 started. ... ... Aug 09, 2018 6:43:22 PM online.tangbk.demo.thead.App main INFO: all thread finished Aug 09, 2018 6:43:22 PM online.tangbk.demo.thead.SubThread run INFO: Thread 8 started. ... ... Aug 09, 2018 6:43:31 PM online.tangbk.demo.thead.SubThread run INFO: Thread 9 end.
import java.util.concurrent.CountDownLatch; import java.util.logging.Logger; public class App { static Logger log = Logger.getAnonymousLogger(); public static void main(String[] args) { // 初始化10个线程的锁 CountDownLatch cdl = new CountDownLatch(10); for (int index = 0; index < 10; index++) { // 将锁传给子线程 new Thread(new SubThread(index, index, cdl)).start(); } try { // 等待全部的锁被(倒数)释放 cdl.await(); } catch (InterruptedException e) { e.printStackTrace(); } // 全部的线程都完成了 log.info("all thread finished"); } }
import java.util.concurrent.CountDownLatch; import java.util.logging.Logger; public class SubThread implements Runnable { private int id; private int waitSecond; private CountDownLatch cdl; static Logger log = Logger.getAnonymousLogger(); public SubThread(int id, int waitSecond, CountDownLatch cdl) { this.id = id; // 秒数*1000毫秒 = 实际等待毫秒数 this.waitSecond = waitSecond * 1000; this.cdl = cdl; } public void run() { try { log.info("Thread " + id + " started."); // 让Thread再飞一下子 Thread.sleep(waitSecond); cdl.countDown(); log.info("Thread " + id + " end."); // 通知完成 } catch (InterruptedException e) { log.config("error"); } } }
能够从结果中看到,全部的线程启动后,都会等到全部线程完成等待后才结束。
Aug 09, 2018 6:29:20 PM online.tangbk.demo.thead.SubThread run INFO: Thread 2 started. Aug 09, 2018 6:29:20 PM online.tangbk.demo.thead.SubThread run INFO: Thread 3 started. Aug 09, 2018 6:29:20 PM online.tangbk.demo.thead.SubThread run INFO: Thread 1 started. Aug 09, 2018 6:29:20 PM online.tangbk.demo.thead.SubThread run INFO: Thread 0 started. ... ... Aug 09, 2018 6:29:28 PM online.tangbk.demo.thead.SubThread run INFO: Thread 8 end. Aug 09, 2018 6:29:29 PM online.tangbk.demo.thead.SubThread run INFO: Thread 9 end. Aug 09, 2018 6:29:29 PM online.tangbk.demo.thead.App main INFO: all thread finished
CountDownLatch(倒数锁)适用于须要等待子线程完成后,统一进行操做的一些操做。更能够结合FutureTask的相关接口,取回子线程的结果,对结果统一搜集处理。