有线程A,B,C,C 要等A和B都执行完了才执行,怎么实现?
LockSupport + AtomicInteger
先执行线程C,用 park() 挂起线程C,线程A、B各自执行完成时,flag 减1并判断是否为0,若为0则用unpark©给线程C颁发许可。
- LockSupport.park() 函数表示挂起当前线程
- LockSupport.unpark© 函数表示解除线程c的阻塞状态
- AtomicInteger.decrementAndGet() 函数表示将该变量减一,并返回当前变量值(线程安全的原子类)
public static void main(String[] args) {
AtomicInteger flag = new AtomicInteger(2);
Thread c = new Thread(()->{
System.out.println("线程C开启,等待线程A、B执行完成才继续执行");
LockSupport.park();
System.out.println("线程C开始执行");
});
c.start();
new Thread(()->{
System.out.println("线程A开始执行");
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程A执行完成");
if (flag.decrementAndGet() == 0){
//唤醒指定线程
LockSupport.unpark(c);
}
}).start();
new Thread(()->{
System.out.println("线程B开始执行");
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程B执行完成");
if (flag.decrementAndGet() == 0){
LockSupport.unpark(c);
}
}).start();
}
CountDownLatch
CountDownLatch 有一个计数器,countDown() 方法对计数器做减操作,await 方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时.
- latch.countDown() 函数将计数器减一
- latch.await() 函数表示,当计数器为0时才接着往下执行,否则陷入阻塞
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(2);
new Thread(() -> {
System.out.println("线程A开始执行");
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程A执行完成");
}).start();
new Thread(() -> {
System.out.println("线程B开始执行");
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
latch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程B执行完成");
}).start();
new Thread(() -> {
System.out.println("线程C开启,等待线程A、B执行完成才继续执行");
try {
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程C执行完成");
}).start();
}
CyclicBarrier
CyclicBarrier 与 CountDownLatch 类似 ,它能阻塞一组线程全部到某个状态再同时执行。 CyclicBarrier 与 CountDownLatch 的关键区别在于,所有的线程必须全部到达位置,才能继续执行。 CountDownLatch 用于等待事件,而 CyclicBarrier 用于等待其他线程,在任意一个线程没有完成之前,所有线程都不能继续执行。
- barrier.await() 函数使当前线程阻塞,直到相应数量的线程都执行到了该函数,才会将所有线程解锁,往下执行
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3);
//只有所有线程执行到了 await(),所有线程才会继续往下执行
new Thread(() -> {
System.out.println("线程A开始执行");
try {
//执行业务
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
System.out.println("线程A执行完成,等待其它线程一起冲破栅栏");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程A执行完成");
}).start();
new Thread(() -> {
System.out.println("线程B开始执行");
try {
//执行业务
TimeUnit.SECONDS.sleep(new Random().nextInt(10));
System.out.println("线程B执行完成,等待其它线程一起冲破栅栏");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程B执行完成");
}).start();
new Thread(() -> {
try {
System.out.println("线程C开启,等待线程AB执行完成一起冲破栅栏");
barrier.await();
//执行业务
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程C执行完成");
}).start();
}