java.util.concurrent包为我们提供了三大辅助类,帮助我们在某些场景下快速编写并发代码。
- CountDownLatch
CountDownLatch(int count)
Constructs a CountDownLatch initialized with the given count.
构造一个用给定计数初始化的CountDownLatch。
CountDownLatch类可以设置一个计数器,然后通过countDown方法来进行减一的操作,使用await方法等待计数器不大于0,然后继续执行await方法之后的语句。
CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。其他线程调用countDown方法会将计数器减一(调用countDown方法的线程不会阻塞)。
当计数器的值变为0时,因await方法而阻塞的线程会被唤醒,继续执行。
案例演示:
import java.util.concurrent.CountDownLatch;
// 演示CountDownLatch
public class CountDownLatchDemo {
// 6个同学陆续离开教室后,班长锁门
public static void main(String[] args) throws InterruptedException {
// 创建CountDownLatch对象,设置初始值
CountDownLatch countDownLatch = new CountDownLatch(6);
// 6个同学陆续离开教室
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() + "班长锁门");
}
}
执行结果:
2. CyclicBarrier
CyclicBarrier(int parties)
Creates a new CyclicBarrier that will trip when the given number of parties (threads) are waiting upon it, and does not perform a predefined action when the barrier is tripped.
创建一个新的CyclicBarrier,当给定数量的参与方(线程)在等待它时,它将触发,并且在触发barrier时不执行预定义的操作。
CyclicBarrier(int parties, Runnable barrierAction)
Creates a new CyclicBarrier that will trip when the given number of parties (threads) are waiting upon it, and which will execute the given barrier action when the barrier is tripped, performed by the last thread entering the barrier.
创建一个新的CyclicBarrier,当给定数量的参与方(线程)在等待它时,它将被绊倒;当barrier被绊倒时,它将执行给定的barrier动作,由最后一个进入barrier的线程执行。
CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时CyclicBarrier很有用。因为该barrier在释放等待线程后可以重用,所以称它为循环栅栏。
CyclicBarrier的构造方法第一个参数是目标障碍数,每次执行CyclicBarrier一次障碍数会加一,如果达到了目标障碍数,才会执行cyclicBarrier.await()之后的语句;可以将CyclicBarrier理解为加一操作。
案例演示:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
// 演示CyclicBarrier
public class CyclicBarrierDemo {
// 集齐7颗龙珠就可以召唤神龙
private static final int NUMBER = 7;
public static void main(String[] args) {
// 创建CyclicBarrier对象
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("集齐7颗龙珠就可以召唤神龙");
});
// 集齐7颗龙珠的过程
for (int i = 1; i <= NUMBER ; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "星龙珠");
// 等待
try {
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
执行结果:
- Semaphore
Semaphore(int permits)
Creates a Semaphore with the given number of permits and nonfair fairness setting.
使用给定的许可数量和非公平性设置创建一个信号量。
Semaphore(int permits, boolean fair)
Creates a Semaphore with the given number of permits and the given fairness setting.
使用给定的许可数量和公平性设置创建一个信号量。
一个计数信号量,从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个acquire方法,然后再获取该许可。每个acquire方法添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,semaphore只对可用许可的号码进行计数,并采取相应的行动。
Semaphore通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
案例演示:
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
// 演示Semaphore
public class SemaphoreDemo {
// 6辆汽车,停3个停车位
public static void main(String[] args) {
// 创建Semaphore,设置许可数量
Semaphore semaphore = new Semaphore(3);
// 模拟6辆汽车
for (int i = 1; i <= 6 ; i++) {
new Thread(() -> {
try {
// 抢占
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 抢到了车位");
// 设置随机停车时间
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName() + " -----离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}
执行结果: