CountDownLatch
- countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
- 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
- CountDownLatch主要有2个方法,当一个或多个线程调用await()方法时,这些线程会阻塞
- 其他线程调用countDown()方法会将计数器减1(调用countDown方法的线程不会阻塞),
- 当计数器变为0时,因await方法阻塞的线程会被唤醒,继续执行
他的构造方法
- 示例
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//假如需要计数6个
CountDownLatch countDownLatch = new CountDownLatch(6);
//6次请求,只有6次请求走完,才输出main线程的操作
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"离开");
//计数器减少1
countDownLatch.countDown();
},String.valueOf(i)).start();
}
//等待计数器归零
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"离开");
}
}
CyclicBarrier
-
CyclicBarrier可循环使用的屏障,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时屏障才会开门 ,所有被屏障拦截的线程才会继续运行。
-
CyclicBarrier和CountDownLatch一样,都是关于线程的计数器,相比CountDownLatch,该JUC辅助类做加法,只要到了规定数,其内部的方法就执行
构造方法
- 示例
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//假如需要计数6个
CountDownLatch countDownLatch = new CountDownLatch(6);
//6次请求,只有6次请求走完,才输出main线程的操作
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"离开");
//计数器减少1
countDownLatch.countDown();
},String.valueOf(i)).start();
}
//等待计数器归零
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"离开");
}
}
Semaphore
Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
信号量一般用2种操作
- acquire(获取):当一个线程调用acquire操作时,它要么通过成功获取信号量(信号量-1), 要么一直等待,直到有现成释放信号量或者超时
- release(释放):实际上会将信号量的值+1,然后唤醒等待的线程
public class SemaphoreDemo {
public static void main(String[] args) {
//3个资源位
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() +"进来了");
//等待3秒
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+"出去了");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 为什么释放要放在finally里呢
// 如果中途出现异常的话,不放在finally里面是有可能不会被执行的,但是放在finally里面是一定会被执行的
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
信号量主要用于
- 共享资源的互斥使用
- 并发线程数的控制 假如Semaphore的初始资源为1,就相当于synchronized