一、CountDownLatch(减少计数)让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒
主要有两个方法,
1.1 当一个或多个线程调用await方法时,这些线程会阻塞,其它线程调用countDown方法会将计数器减一(调用countDown方法的线程不会阻塞);
1.2 当计数器的值变为0时,await方法阻塞的线程会被唤醒,继续执行
示例代码:
import java.util.concurrent.CountDownLatch;
/**
* 解释:8个饭桶陆续离开食堂后扫地僧才可以关灯
*
* main主线程必须要等前面8个线程完成全部工作后,自己才能开干
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
//8个在食堂的同学,各自离开食堂的时间不一致
for (int i = 1; i <= 8; i++){
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 号饭桶离开食堂");
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "\t****** 扫地僧关灯走人");
}
}
二、CyclicBarrier(循环栅栏)可循环(Cyclic)使用的屏障(Barrier)
作用:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
*
* 集齐5福瓜分5亿
*/
public class CyclicBarrierDemo {
private static final int NUMBER = 7;
public static void main(String[] args) {
//CyclicBarrier(int parties, Runnable barrierAction)
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("*****集齐5福瓜分5亿");
});
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "\t 张福被收集 ");
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
三、Semaphore(信号量)用于多个共享资源的互斥使和控制并发线程数
3.1 acquire(获取) 当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时;
3.2 release(释放)实际上会将信号量的值加1,然后唤醒等待的线程。
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
*
* 厕所占坑
*/
public class SemaphoreDemo {
public static void main(String[] args) {
//设置5个坑位
Semaphore semaphore = new Semaphore(5);
//设置9个人拉屎
for (int i = 1; i <= 9; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t 抢到了坑位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + "\t------- 离开");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}