全文概要
本文将介绍并发库中三个线程辅助类,CountDownLatch、CyclicBarrier和Semaphore。本文主要内容如下:
- 通过一个案例介绍CountDownLatch的用法和使用场景;
- 通过一个案例介绍CyclicBarrier的用法和使用场景;
- 通过一个案例介绍Semaphore的用法和使用场景。
CountDownLatch
- CountDownLatch简介
CountDownLatch的有一个计数器,每隔线程执行都会将这个计数器减1,当计数器为0时,当前线程才能继续执行;
- 代码案例
package com.tml.javaCore.concurrent;
import java.util.concurrent.CountDownLatch;
/**
* <p>介绍concurrent包中一个多线程辅助类CountDownLatch的使用
* @author Administrator
*
*/
public class CountDownLatchDemo {
private static final int SIZE = 5;
private static CountDownLatch countDownLatch = new CountDownLatch(SIZE);
public static void main(String[] args) {
CountDownLatchDemo demo = new CountDownLatchDemo();
try {
for(int i=0;i<SIZE;i++){
//新建5个线程
new Thread(new Runnable() {
public void run() {
demo.work();
}
}, "thread_0" + (i+1)).start();
}
//主线程等待,当五个线程的任务执行完成后,才继续执行主线程后续的逻辑
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + " end!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void work(){
try {
System.out.println(Thread.currentThread().getName() + " ready to sleep 1s");
Thread.sleep(1000);
//将countDownLatch的数值减一
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 结果输出
thread_01 ready to sleep 1s
thread_02 ready to sleep 1s
thread_04 ready to sleep 1s
thread_03 ready to sleep 1s
thread_05 ready to sleep 1s
main end!
- 结果分析
- 新建了一个CountDownLatch对象,它的计数器是5,主线程中创建了五个线程;
- 调用线程的start()方法启动线程后,主线程执行countDownLatch.await(),表示主线程必须等待countDownLatch对象的计数器置为0,才能继续秩序执行;
- 五个线程分别执行work()方法,调用countDownLatch.countDown()的作用是将计数器减1;
- 当五个线程全部执行完毕后,即countDownLatch的计数器为0,此时唤醒主线程,主线程继续执行后续逻辑。
CyclicBarrier
- CyclicBarrier简介
CyclicBarrier对象创建的时候,需要定义一个参与者数量,调用该对象的await()方法,会将参与者数量加1,同时线程进入阻塞状态。只有当CyclicBarrier对象的参与者数量和定义的参与者数量一致时,才会重新唤醒被阻塞的线程,让其继续执行后续逻辑。
- 代码案例
package com.tml.javaCore.concurrent;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* <p>介绍concurrent包中一个多线程辅助类CyclicBarrier的使用
* @author Administrator
*
*/
public class CyclicBarrierDemo {
private static final int SIZE = 5;
//新建一个barrier1对象,它将在给定数量的线程处于等待状态下执行
private static CyclicBarrier barrier1 = new CyclicBarrier(SIZE);
//新建一个barrier1对象,它将在给定数量的线程处于等待状态下执行,同时执行runnable里面的任务
private static CyclicBarrier barrier2 = new CyclicBarrier(SIZE,new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + " barrier to go!");
}
});
public static void main(String[] args) {
CyclicBarrierDemo demo = new CyclicBarrierDemo();
System.out.println(Thread.currentThread().getName() + " start!");
for(int i=1;i<=SIZE;i++){
new Thread(new Runnable() {
public void run() {
demo.work();
}
},"thread_0" + i).start();
}
System.out.println(Thread.currentThread().getName() + " end!");
}
private void work(){
System.out.println(Thread.currentThread().getName() + " is waiting for barrier!");
try {
System.out.println(Thread.currentThread().getName() +
" is working !");
Thread.sleep(1000);
//将barrier的参与者加1
barrier1.await();
//当barrier的参与者达到SIZE的时候,执行后续逻辑
System.out.println(Thread.currentThread().getName() + "continue....");
} catch (BrokenBarrierException e) {
e.printStackTrace();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 结果输出
使用barrier1对象的输出:
main start!thread_01 is waiting for barrier!
thread_01 is working !
thread_03 is waiting for barrier!
main end!
thread_02 is waiting for barrier!
thread_03 is working !
thread_02 is working !
thread_04 is waiting for barrier!
thread_04 is working !
thread_05 is waiting for barrier!
thread_05 is working !
thread_05continue....
thread_02continue....
thread_03continue....
thread_04continue....
thread_01continue....
使用barrier2对象的输出:
main start!thread_01 is waiting for barrier!
main end!
thread_03 is waiting for barrier!
thread_03 is working !
thread_02 is waiting for barrier!
thread_02 is working !
thread_01 is working !
thread_04 is waiting for barrier!
thread_05 is waiting for barrier!
thread_04 is working !
thread_05 is working !
thread_05 barrier to go!
thread_05continue....
thread_03continue....
thread_01continue....
thread_04continue....
thread_02continue....
- 结果分析
- 闯进CyclicBarrier对象的时候,有两个构造方法。barrier1对象表示有5个参与者,当参与者的数量达到5时执行;barrier1对象表示有5个参与者,当参与者的数量达到5时,先执行runnable里面的任务,接着执行线程后续逻辑;
- 主线程中用循环创建了5个线程,启动线程,主线程执行完毕;
- 5个线程分别执行work()方法,执行await()方法时,将参与者数量加1,同时该线程进入阻塞,只有当barrier对象的参与者数量达到5时,才会唤醒该线程;
- 唤醒线程的时候,若采用barrier1对象则直接执行线程后续逻辑,若barrier2则先会执行runnable()里面的任务再执行线程里面的后续代码。
Semaphore
- Semaphore简介
Semaphore的作用是在相同的时刻,最多能允许指定数量的线程执行,若并发的线程数量大于指定的线程数,则多余的线程必须等待,直到有线程任务执行完毕后,该线程才有机会执行。
- 代码案例
package com.tml.javaCore.concurrent;
import java.util.concurrent.Semaphore;
/**
* <p>介绍concurrent包中一个多线程辅助类Semaphore的使用
* @author Administrator
*
*/
public class SemaphoreDemo {
//新建一个容量为2的信号量,意义是同时只能允许两个线程并发
private static Semaphore semaphore =new Semaphore(2);
public static void main(String[] args) {
SemaphoreDemo demo = new SemaphoreDemo();
//创建3个线程,小于semaphore的信号量,所以,同时只能有两个线程执行,只有等其中一个线程执行完毕了,第三个线程才能执行
for(int i=1;i<=3;i++){
new Thread(new Runnable() {
public void run() {
demo.work();
}
}, "thread_0" + i).start();
}
}
private void work(){
try {
//在semaphore申请一个信号量
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " ready to work!");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " end to work!");
//释放掉刚刚申请的semaphore信号量
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 结果输出
thread_02 ready to work!
thread_01 end to work!
thread_02 end to work!
thread_03 ready to work!
thread_03 end to work!
- 结果分析
- 创建一个容量为2的信号量对象semaphore,意义是同时只能允许两个线程并发;
- 主线程中创建了三个线程,启动线程,主线程执行完毕;
- 三个线程分别执行work()方法,执行work方法时先调用semaphore.acquire(),意义是在semaphore申请一个信号量,执行work方法结束前调用semaphore.release(),意义是释放掉刚刚申请的semaphore信号量;
- 结果是只能两个线程并发执行,第三个线程只能等待其中一个线程执行完毕后,才能执行。