本文将介绍并发编程中的线程同步工具。
一、CountDownLatch
1. 作用
适用于一个线程等待多个线程的场景,通过计数的方式解决问题。
2. 示例
假设有这样一个需求:当前线程需要等待线程 T1 和 T2 执行某些操作。
显然,我们可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Test { public static void main(String[] args) { Thread thread1 = new Thread(() -> { Thread.sleep(1000); System.out.println(1); }); thread1.start(); Thread thread2 = new Thread(() -> { Thread.sleep(500); System.out.println(2); }); thread2.start(); thread1.join(); thread2.join(); System.out.println(3); }
}
|
但是当线程不会销毁时(例如通过线程池进行的多线程执行),join()
方法便无法使用。
可以通过 CountDownLatch 解决这一问题,具体使用方法如下:
- 首先实例化 CountDownLatch,传入需要等待的线程数
- 若需要等待的子线程执行完成,应该调用
countDownLatch.countDown()
方法使计数器递减
- 在主线程中使用
countDownLatch.await()
方法,等待直至计数器归零
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Test2 { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(2); Executor executor = Executors.newFixedThreadPool(2); executor.execute(() -> { Thread.sleep(1000); System.out.println(1); countDownLatch.countDown(); }); executor.execute(() -> { Thread.sleep(1000); System.out.println(1); countDownLatch.countDown(); }); countDownLatch.await(); System.out.println(3); }
}
|
二、CyclicBarrier
1. 作用
适用于多个线程 “同步前进” 场景。
2. 示例
假设有这样一个需求:线程 T1 和 T2 共同循环完成一个任务,且两个线程应该保持同步(T1 完成且 T2 完成后,才能进行下一轮循环)。
如果不引入额外的机制,假如 T1 与 T2 的每轮执行所需时间不同,则两个线程将彻底丧失同步,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Test { public static void main(String[] args) { Thread thread1 = new Thread(() -> { while (true) { Thread.sleep(1000); System.out.println(1); } }); thread1.start(); Thread thread2 = new Thread(() -> { while (true) { Thread.sleep(500); System.out.println(2); } }); thread2.start(); }
}
|
可以通过 CyclicBarrier 解决这一问题,具体使用方法如下:
- 首先实例化 CyclicBarrier,传入 “同步前进” 的线程数
- 若线程执行完成,应该调用
cyclicBarrier.await()
方法等待其它 “同步前进” 的线程执行完成
- 当所有的线程都调用
cyclicBarrier.await()
方法后,cyclicBarrier 将重置,并允许所有线程继续执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Test2 { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(2); Thread thread1 = new Thread(() -> { while (true) { Thread.sleep(1000); System.out.println(1); cyclicBarrier.await(); } }); thread1.start(); Thread thread2 = new Thread(() -> { while (true) { Thread.sleep(500); System.out.println(2); cyclicBarrier.await(); } }); thread2.start(); }
}
|
参考