四个类可协助实现常见的专用同步语句。Semaphore 是一个经典的并发工具。CountDownLatch 是一个极其简单但又极其常用的实用工具,用于在保持给定数目的信号、事件或条件前阻塞执行。CyclicBarrier 是一个可重置的多路同步点,在某些并行编程风格中很有用。Exchanger 允许两个线程在 collection 点交换对象,它在多流水线设计中是有用的。
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
等待其他线程:CountDownLatch(其实就是个倒序计数器)
当其他线程完成之前,该类线程一直处于等待状态.
场景需求:
起点裁判倒计时....之后 运动员起跑,然后终点裁判发布成绩.
要让起点裁判线程优先执行.
老师开始给出了一个线程的join方法可以实现这个需求. t.join(); // 优先执行当前线程
但是join不好,因为如果t对应的线程不执行完,其他的所有线程都不会被执行到.
可以使用CountDownLatch.
final CountDownLatch cdl1 = new CountDownLatch(1);
刚开始让4个运动员线程处于等待状态,然后判断,有一个计数器int i = 1,裁判线程获得这个计数器.
裁判执行完对应的代码之后,把i变成0,如果运动员获得i=0,就开始执行.
要等到最后一个运动员线程执行完,终点裁判宣布成绩.
定义一个初始值是4的计数器,有个运动员到终点就减去1(cdl1.countDown();// 计数器减1).
cdl2.await();// 等待计数器变为0
CountDownLatchDemo.java
1 import java.util.Random; 2 import java.util.concurrent.CountDownLatch; 3 import java.util.concurrent.TimeUnit; 4 5 public class CountDownLatchDemo { 6 7 public static void main(String[] args) throws InterruptedException { 8 final CountDownLatch cdl1 = new CountDownLatch(1); 9 final CountDownLatch cdl2 = new CountDownLatch(4); 10 11 // t.join(); // 优先执行当前线程 12 13 for (int i = 0; i < 4; i++) { 14 new Thread(new Runnable() {// 运动员 15 16 @Override 17 public void run() { 18 try { 19 cdl1.await(); // 等待计数器变为0 20 21 System.out.println(Thread.currentThread() 22 .getName() + " : 起跑"); 23 TimeUnit.SECONDS.sleep(new Random().nextInt(3)); 24 System.out.println(Thread.currentThread() 25 .getName() + " : 到达终点!"); 26 cdl2.countDown(); 27 } catch (InterruptedException e) { 28 e.printStackTrace(); 29 } 30 } 31 }).start(); 32 } 33 34 Thread t = new Thread(new Runnable() {// 发布命令的裁判 35 36 @Override 37 public void run() { 38 System.out.println("准备"); 39 for (int i = 3; i >= 1; i--) { 40 System.out.println(i + "..."); 41 try { 42 TimeUnit.SECONDS.sleep(1); 43 } catch (InterruptedException e) { 44 e.printStackTrace(); 45 } 46 } 47 System.out.println("跑!"); 48 cdl1.countDown();// 计数器减1 49 50 } 51 }); 52 t.start(); 53 54 new Thread(new Runnable() {// 宣布成绩的裁判 55 56 @Override 57 public void run() { 58 try { 59 cdl2.await();// 等待计数器变为0 60 } catch (InterruptedException e) { 61 e.printStackTrace(); 62 } 63 System.out.println("宣布成绩!"); 64 } 65 }).start(); 66 67 } 68 }