4-15-cyclicBarrier-countdownlatch-semaphore

文章目录
  1. 1. countdownlatch线程计数器(等待所有线程搞定,主线程才继续)
    1. 1.1. 用法
  2. 2. cyclicBarrier(回环栅栏,让一组线程等待至某个状态之后再全部同时执行)
    1. 2.1. 回环
    2. 2.2. barrier
    3. 2.3. 用法
  3. 3. semaphore信号量(控制同时访问线程个数)
    1. 3.1. 用法
  4. 4. 使用场景

countdownlatch线程计数器(等待所有线程搞定,主线程才继续)

用法

比如有一个任务 A,它要等待其他 4 个任务执行完毕之后才能执行,此时就可以利用CountDownLatc来实现这种功能了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final CountDownLatch latch = new CountDownLatch(2);
new Thread(){public void run() {
System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
Thread.sleep(3000);
System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
latch.countDown();
};}.start();
new Thread(){ public void run() {
System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
Thread.sleep(3000);
System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
latch.countDown();
};}.start();

System.out.println("等待 2 个子线程执行完毕...");

latch.await();

System.out.println("2 个子线程已经执行完毕");
System.out.println("继续执行主线程");
}

cyclicBarrier(回环栅栏,让一组线程等待至某个状态之后再全部同时执行)

回环

因为当所有等待线程都被释放以后,CyclicBarrier 可以被重用。

barrier

当调用 await()方法之后,线程就处于 barrier 了。

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) {
int N = 4;
CyclicBarrier barrier = new CyclicBarrier(N);
for(int i=0;i<N;i++)
new Writer(barrier).start();
}
static class Writer extends Thread{
private CyclicBarrier cyclicBarrier;
public Writer(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
Thread.sleep(5000); //以睡眠来模拟线程需要预定写入数据操作
System.out.println("线程"+Thread.currentThread().getName()+"写入数据完
毕,等待其他线程写入完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
}catch(BrokenBarrierException e){
e.printStackTrace();
}
System.out.println("所有线程写入完毕,继续处理其他任务,比如数据操作");
}
}

semaphore信号量(控制同时访问线程个数)

Semaphore 可以控制同时访问的线程个数,通过acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

用法

例子:若一个工厂有 5 台机器,但是有 8 个工人,一台机器同时只能被一个工人使用,只有使用完
了,其他工人才能继续使用。那么我们就可以通过 Semaphore 来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 int N = 8; //工人数
Semaphore semaphore = new Semaphore(5); //机器数目
for(int i=0;i<N;i++)
new Worker(i,semaphore).start();
}
static class Worker extends Thread{
private int num;
private Semaphore semaphore;
public Worker(int num,Semaphore semaphore){
this.num = num;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("工人"+this.num+"占用一个机器在生产...");
Thread.sleep(2000);
System.out.println("工人"+this.num+"释放出机器");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
} }

使用场景

CountDownLatch 和 CyclicBarrier 都能够实现线程之间的等待,只不过它们侧重点不同;

  1. CountDownLatch 一般用于某个线程 A 等待若干个其他线程执行完任务之后,它才执行;
  2. CyclicBarrier 一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;另外,CountDownLatch 是不能够重用的,而 CyclicBarrier 是可以重用的。
  3. Semaphore 其实和锁有点类似,它一般用于控制对某组资源的访问权限。