目录
一. CountDownLatch
CountDownLatch 是 JDK5 之后加入的一种并发流程控制工具,它在 java.util.concurrent 包下,是能使一组线程等另一组线程都跑完了再继续跑。
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 1; i <= 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程" +
Thread.currentThread().getName() + "开始运行");
countDownLatch.countDown();
}
}, "t" + i).start();
}
countDownLatch.await();
System.out.println("主线程最后执行-------------");
}
运行结果:
线程t1开始运行
线程t4开始运行
线程t2开始运行
线程t3开始运行
线程t6开始运行
主线程最后执行-------------
从结果可以得出,CountDownLatch可以控制线程执行先后,也就是调用了CountDownLatch.await()的线程直到countDown计数器为0后才可以执行。但是现在更喜欢用CompletableFuture来控制线程运行顺序
二. CyclicBarrier
CyclicBarrier的字面意思是可循环的(Cyclic)的使用屏障(Barrier)。它主要做的事情是让一组线程到达一个屏障点(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障是通过CyclicBarrier的await方法实现的。
CyclicBarrier可以使一定数量的线程反复地在屏障位置处汇集。当线程到达屏障位置时将调用await方法,这个方法将阻塞直到所有线程都到达屏障位置。如果所有线程都到达屏障位置,那么屏障将打开,此时所有的线程都将被释放。
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Thread(new Runnable() {
@Override
public void run() {
System.out.println("开始吃饭");
}
}));
for (int i = 1; i <= 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() +
"进入餐厅");
// 被阻塞,等待所有的线程都进入餐厅
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}, "t"+ i).start();
}
}
}
运行结果:
t1进入餐厅
t4进入餐厅
t5进入餐厅
t3进入餐厅
t2进入餐厅
开始吃饭
从结果可以看出,当所有的线程都调用了 await方法,cyclicBarrier构造方法的线程才会执行,同时所有调用await方法的线程同时被唤醒,继续执行下面的操作
注意 :
CyclicBarrier的构造方法,可以传入一个实现了Runnable接口的类,表示,当所有的线程都调用了await,该线程才会被被执行。
CyclicBarrier的构造方法也可以只传入一个int类型的数字,表示当所有的线程(传入的参数数字的线程)都调用了await,所有的调用了await方法的线程都会被唤醒,继续执行下面的代码。
三. Semaphore
字面意思为 信号量,Semaphore能够控同时访问的线程个数,经过 acquire() 获取一个许可,若是没有就等待,而 release() 释放一个许可。
public static void main(String[] args) {
// 表示3个车位
Semaphore semaphore = new Semaphore(3);
// 创建5个线程,一个线程代表一辆车
for (int i = 1; i <= 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 获得许可,在获取许可前该线程将一直阻塞在此,表示抢占车位
semaphore.acquire();
System.out.println(Thread.currentThread().getName() +
" 占用了车位");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() +
" 停车3秒离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 表示释放一个许可,表示离开车位
semaphore.release();
}
}
}, "t"+i).start();
}
}
运行结果:
t1 占用了车位
t2 占用了车位
t3 占用了车位
t1 停车3秒离开车位
t2 停车3秒离开车位
t3 停车3秒离开车位
t4 占用了车位
t5 占用了车位
t4 停车3秒离开车位
t5 停车3秒离开车位
从运行结果可知,同时只能有3个线程(即车)进入停车,离开一辆车才能进来一辆车。
即semaphore.acquire()和semaphore.release()包起来的代码块,同时只能有3个线程进来,其他线程进来必须等待里面的线程执行完释放了资源,才能进入。
semaphore和synchronize的区别:
semaphore:可以控制多个线程进入,也可以是一个线程进入代码块
synchronize:只能控制一个线程计入代码块
总结:
Semaphore主要用于控制当前活动线程数目,就如同停车场系统一般,而Semaphore则相当于看守的人,用于控制总共允许停车的停车位的个数,而对于每辆车来说就如同一个线程,线程需要通过acquire()方法获取许可,而release()释放许可。如果许可数达到最大活动数,那么调用acquire()之后,便进入等待队列,等待已获得许可的线程释放许可,从而使得多线程能够合理的运行。
四. Exchanger
Exchanger是java 5引入的并发类,Exchanger顾名思义就是用来做交换的。这里主要是两个线程之间交换持有的对象。当Exchanger在一个线程中调用exchange方法之后,会等待另外的线程调用同样的exchange方法。
两个线程都调用exchange方法之后,传入的参数就会交换。
具体示例:
@Data
public class Book {
private String name;
}
@Slf4j
public class ExchangerOne implements Runnable{
Exchanger<Book> ex;
ExchangerOne(Exchanger<Book> ex){
this.ex = ex;
}
@Override
public void run() {
Book book= new Book();
book.setName("book one");
try {
Book exhangeBook = ex.exchange(book);
log.info(exhangeBook.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Slf4j
public class ExchangerTwo implements Runnable {
Exchanger<Book> ex;
ExchangerTwo(Exchanger<Book> ex){
this.ex = ex;
}
@Override
public void run() {
Book book = new Book();
book.setName("book two");
try {
CustBook exhangeBook = ex.exchange(book);
log.info(exhangeBook.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ExchangerUsage {
public static void main(String[] args) {
Exchanger<Book> exchanger = new Exchanger<>();
// Starting two threads
new Thread(new ExchangerOne(exchanger)).start();
new Thread(new ExchangerTwo(exchanger)).start();
}
}
运行结果:
22:14:09.069 [Thread-1] INFO com.lm.mrluo735.ExchangerTwo - book one
22:14:09.073 [Thread-0] INFO com.lm.mrluo735.ExchangerOne - book two
可以看到对象已经被交换了。
文章介绍了Java并发编程中的四种工具类:CountDownLatch用于线程等待,CyclicBarrier实现线程同步,Semaphore控制并发线程数量,Exchanger用于线程间数据交换。每个工具类都有其特定的使用场景和示例代码演示。
265

被折叠的 条评论
为什么被折叠?



