Java-JUC(十二):有3个线程。线程A和线程B并行执行,线程C需要A和B执行完成后才能执行。可以怎么实现?
方案(一)CountDownLatch:
使用CountDownLatch+Semaphore方式实现:
import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; public class TestABC { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch=new CountDownLatch(2); Semaphore semaphoreC = new Semaphore(1); Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(newjava.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(newjava.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-B"); Thread threadC = new Thread(new Runnable() { @Override public void run() { try { semaphoreC.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); semaphoreC.release(); } }, "Thread-C"); // 占用C锁,直到A/B线程完成后,才释放C锁。 semaphoreC.acquire(); threadA.start(); threadB.start(); threadC.start(); countDownLatch.await(); // 释放C锁,让C线程有获取锁的可能 semaphoreC.release(); } }
上边使用CountDownLatch+Semaphore方式实现,但是缺点:上边这种方式会导致线程阻塞情况。下边这种方案是可以实现不阻塞线程的用法:
import java.util.concurrent.CountDownLatch; public class TestABC { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch=new CountDownLatch(2); Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); countDownLatch.countDown(); } }, "Thread-B"); Thread threadC = new Thread(new Runnable() { @Override public void run() { // 在C中等待A/B運算結束 try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); throw new RuntimeException("CountDownLatch等待失败。。。",e); } System.out.println(Thread.currentThread().getName()); } }, "Thread-C"); threadA.start(); threadB.start(); threadC.start(); } }
方案(二):CyclicBarrier
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class TestABC { public static void main(String[] args) throws InterruptedException { CyclicBarrier cyclicBarrier=new CyclicBarrier(3); Thread threadA = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); // 冲破栅栏代表A线程结束 try { cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); throw new RuntimeException("cylicBarrier.await()拋出異常:",e); } } }, "Thread-A"); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(new java.util.Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); // 冲破栅栏代表B线程结束 try { cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); throw new RuntimeException("cylicBarrier.await()拋出異常:",e); } } }, "Thread-B"); Thread threadC = new Thread(new Runnable() { @Override public void run() { // 等待前两个(A/B)线程结束,只有前两个(A/B)线程结束了才能满足3个线程都冲破栅栏, try { // 等待栅栏被冲破,冲破栅栏的条件是:A/B/C三个线程都到达await()。 // 只有栅栏冲破,才能向下执行,否则先到达的线程等待。 cyclicBarrier.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); throw new RuntimeException("cylicBarrier.await()拋出異常:",e); } // 满足了三个线程都冲破栅栏才向下执行 System.out.println(Thread.currentThread().getName()); } }, "Thread-C"); threadA.start(); threadB.start(); threadC.start(); } }
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。