CountDownLatch
CountDownLatch可以用来实现一个(或者多个)线程等待其他线程完成一组特定的操作之后才继续运行。
CountDownLatch是一种灵活的闭锁实现。闭锁状态包括一的计数器,该计数器被初始化为一个整数,表示需要等待执行的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,这表示所有需要等待的事件都已经发生。如果计数器的值非零,那么await会一直阻塞直到计数器为零,或者等待中的线程中断,或者等待超时。
示例代码(1):
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo implements Runnable {
static final CountDownLatch end = new CountDownLatch(10);
static final CountDownLatchDemo demo = new CountDownLatchDemo();
@Override
public void run() {
try {
// 模拟检查消费时间
Thread.sleep(new Random().nextInt(10) * 1000);
System.out.println("check complete");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
end.countDown();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
exec.submit(demo);
}
// 等待检查
end.await();
// 检查完成
System.out.println("Fire!");
exec.shutdown();
}
}
output:
check complete
check complete
check complete
check complete
check complete
check complete
check complete
check complete
check complete
check complete
Fire!
示例代码(2):
import java.util.Random;
import java.util.concurrent.CountDownLatch;
class A implements Runnable {
@Override
public void run() {
// 获取的时间是纳秒,1秒等于10的负9次方秒
long start = System.nanoTime();
long time = new Random().nextInt(10) * 1000;
System.out.println(Thread.currentThread().getName() + " Sleep: " + time);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.nanoTime();
System.out.println(Thread.currentThread().getName() + " 执行耗时:" + (end - start));
}
}
public class TestHarness {
public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(nThreads);
for (int i = 0; i < nThreads; i++) {
Thread t = new Thread() {
@Override
public void run() {
try {
startGate.await();
try {
task.run();
} finally {
endGate.countDown();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
long start = System.nanoTime();
// 开始运行
startGate.countDown();
// 等待直到每个线程运行结束
endGate.await();
long end = System.nanoTime();
return end - start;
}
public static void main(String[] args) throws InterruptedException {
TestHarness t = new TestHarness();
System.out.println("耗时:" + t.timeTasks(10, new A()));
}
}
output:
Thread-2 Sleep: 4000
Thread-0 Sleep: 3000
Thread-8 Sleep: 7000
Thread-1 Sleep: 5000
Thread-5 Sleep: 2000
Thread-6 Sleep: 2000
Thread-4 Sleep: 8000
Thread-9 Sleep: 4000
Thread-3 Sleep: 3000
Thread-7 Sleep: 3000
Thread-5 执行耗时:2005204200
Thread-6 执行耗时:2005141375
Thread-0 执行耗时:3005266455
Thread-3 执行耗时:3005240876
Thread-7 执行耗时:3005126067
Thread-2 执行耗时:4005235456
Thread-9 执行耗时:4005301628
Thread-1 执行耗时:5005144318
Thread-8 执行耗时:7005070658
Thread-4 执行耗时:8005212250
耗时:8005570200
CyclicBarrier
CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier很有用。因为该barrier在释放等待线程后可以重用,所以称它为循环的barrier。
CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier数的是调用了CyclicBarrier.await()进入等待的线程数, 当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。 CyclicBarrier就象它名字的意思一样,可看成是个栅栏,所有的线程必须到齐后才能一起通过这个栅栏。 CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程执行结束后被执行。
方法 | 签名 | 中文说明 |
---|---|---|
构造方法摘要 | CyclicBarrier(int parties) | 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个 barrier 上执行预定义的操作。 |
构造方法摘要 | CyclicBarrier(int parties, Runnable barrierAction) | 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行 |
方法摘要 | int await( ) | 在所有参与者都已经在此barrier上调用await方法之前,将一直等待。 |
方法摘要 | int await(long timeout, TimeUnit unit) | 在所有参与者都已经在此屏障上调用 await 方法之前,将一直等待。 |
方法摘要 | int getNumberWaiting( ) | 返回当前在屏障处等待的参与者数目。 |
方法摘要 | int getParties( ) | 返回要求启动此 barrier 的参与者数目。 |
方法摘要 | boolean isBroken( ) | 查询此屏障是否处于损坏状态。 |
方法摘要 | void reset( ) | 将屏障重置为其初始状态。 |
示例代码:
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static class Solider implements Runnable {
private String soldier;
private final CyclicBarrier cyclic;
public Solider(CyclicBarrier cyclic, String soldier) {
this.soldier = soldier;
this.cyclic = cyclic;
}
@Override
public void run() {
try {
// 等待所有士兵到齐
cyclic.await();
doWork();
// 等待所有士兵完成工作(循环启用)
cyclic.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
void doWork() {
try {
Thread.sleep(Math.abs(new Random().nextInt() % 10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(soldier + ":任务完成!");
}
}
public static class BarrierRun implements Runnable {
boolean flag;
int N;
public BarrierRun(boolean flag, int N) {
this.flag = flag;
this.N = N;
}
@Override
public void run() {
if (flag) {
System.out.println("司令:【士兵" + N + "个,任务完成!】");
} else {
System.out.println("司令:【士兵" + N + "个,集合完毕!】");
flag = true;
}
}
}
public static void main(String[] args) {
final int N = 10;
Thread[] allSoldier = new Thread[N];
boolean flag = false;
CyclicBarrier cyclic = new CyclicBarrier(N, new BarrierRun(flag, N));
// 设置屏障点,主要是为了执行这个方法
System.out.println("集合队伍!");
for (int i = 0; i < N; i++) {
System.out.println("士兵 " + i + " 报道!");
allSoldier[i] = new Thread(new Solider(cyclic, "士兵 " + i));
allSoldier[i].start();
}
}
}
output:
集合队伍!
士兵 0 报道!
士兵 1 报道!
士兵 2 报道!
士兵 3 报道!
士兵 4 报道!
士兵 5 报道!
士兵 6 报道!
士兵 7 报道!
士兵 8 报道!
士兵 9 报道!
司令:【士兵10个,集合完毕!】
士兵 9:任务完成!
士兵 5:任务完成!
士兵 3:任务完成!
士兵 0:任务完成!
士兵 6:任务完成!
士兵 1:任务完成!
士兵 2:任务完成!
士兵 8:任务完成!
士兵 7:任务完成!
士兵 4:任务完成!
司令:【士兵10个,任务完成!】
示例代码:
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
//创建CyclicBarrier对象并设置3个公共屏障点
final CyclicBarrier cb = new CyclicBarrier(3);
for (int i = 0; i < 3; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
//到此如果没有达到公共屏障点,则该线程处于等待状态,如果达到公共屏障点则所有处于等待的线程都继续往下运行
cb.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
output:
线程pool-1-thread-1即将到达集合地点1,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点1,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点1,当前已有2个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有0个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点2,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有2个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有0个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点3,当前已有1个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点3,当前已有2个已经到达,正在等候
Exchanger
Exchanger可以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据。
当线程A调用Exchange对象的exchange()方法后,他会陷入阻塞状态,直到线程B也调用了exchange()方法,然后以线程安全的方式交换数据,之后线程A和B继续运行。
示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Exchanger;
/**
* 生产者
*/
class Producer extends Thread {
List<Integer> list = new ArrayList<>();
Exchanger<List<Integer>> exchanger;
public Producer(Exchanger<List<Integer>> exchanger) {
super();
this.exchanger = exchanger;
}
@Override
public void run() {
Random rand = new Random();
for (int i = 0; i < 10; i++) {
list.clear();
list.add(rand.nextInt(10000));
list.add(rand.nextInt(10000));
list.add(rand.nextInt(10000));
list.add(rand.nextInt(10000));
list.add(rand.nextInt(10000));
try {
list = exchanger.exchange(list);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者
*/
class Consumer extends Thread {
List<Integer> list = new ArrayList<>();
Exchanger<List<Integer>> exchanger;
public Consumer(Exchanger<List<Integer>> exchanger) {
super();
this.exchanger = exchanger;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
list = exchanger.exchange(list);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(list.get(0) + ", ");
System.out.print(list.get(1) + ", ");
System.out.print(list.get(2) + ", ");
System.out.print(list.get(3) + ", ");
System.out.println(list.get(4) + ", ");
}
}
}
public class Exam3 {
public static void main(String[] args) {
Exchanger<List<Integer>> exchanger = new Exchanger<>();
new Consumer(exchanger).start();
new Producer(exchanger).start();
}
}