这篇文章我们来介绍几个并发编程常用的工具类,它们分别是:CountDownLatch(闭锁,我觉得叫门闩更好理解)

CyclicBarrier(栅栏)

Semophore(信号量)

Exchanger(交换器)闭锁

适用场景:在多线程执行过程中设置几个门闩,当所有的门闩被打开时,被挡在门外的线程才能继续执行。

例子代码:

import java.util.concurrent.*;
public class Demo {
public static void main(String[] args) throws Exception{
System.out.println(Util.testTime(3, new Runnable() {
@Override
public void run() {
System.out.println("test");
}
}));
}
}
class Util{
/*** 测试n个线程并发执行某个任务的时间* @param nThreads 线程数量* @param task 需要并发执行的任务* @return* @throws InterruptedException*/
public static long testTime(int nThreads,final Runnable task) throws InterruptedException {
//为启动门设置一个门闩,当门闩被打开时,放行所有被挡在门外的线程 final CountDownLatch startGate=new CountDownLatch(1);
//为结束门设置n个门闩,当n个门闩被打开时,放行所有被挡在门外的线程 final CountDownLatch endGate=new CountDownLatch(nThreads);
//测试n个线程并发执行任务task的时间 for(int i=0;i
Thread t=new Thread(){
public void run(){
try {
startGate.await();
task.run();
endGate.countDown();
} catch (InterruptedException e) {
endGate.countDown();
}
}
};
t.start();
}
//循环中的内容使得有n个线程在startGate门外等着执行task任务 long start=System.nanoTime();
startGate.countDown();//打开startGate上的门闩 endGate.await();//等待endGate门开 long end =System.nanoTime();
return end-start;
}
}
2. 栅栏
使用场景:多个线程彼此等待,当所有的线程都到达指定“地点”(指定代码位置),才开始继续执行。
例子代码:
public class Demo{
public static void main(String [] args) throws InterruptedException {
final CyclicBarrier cyclicBarrier=new CyclicBarrier(10, new Runnable() {
@Override
public void run() {
System.out.println("10个人都到达会议室,开始开会");
}
});
for(int i=0;i<10;i++){
final long tmp=i;
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000*(11-tmp));
System.out.println("person"+tmp+" come here");
try {
cyclicBarrier.await();//等待其他线程到达
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {}
}
});
thread.start();
}
}
}
CountDownLatch和CyclicBarrier这两个类常常容易混淆。但实际上不难区分:CountDownLatch是用来为多个线程设置障碍,在障碍没被消除前,所有的线程必须等候,是“攻坚克难”(障碍解决后才能开会);而CyclicBarrier是对所有的线程进行统筹协调,是“缺一不可”(大家都在才能开会)。
3. 信号量
使用场景:需要控制访问某个资源或者进行某种操作的线程数量。当达到指定数量时,只能等待其他线程释放信号量。
例子代码:
public class Demo{
private static Semaphore semaphore=new Semaphore(2);
public static void main(String [] args) throws InterruptedException {
ExecutorService executorService=Executors.newFixedThreadPool(4);
for(int i=0;i<4;i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
try {
Demo.doSomething();
}catch (InterruptedException e){
System.out.println(Thread.currentThread().getName()+" can't get semaphore.");
}
}
});
}
executorService.shutdown();
while(true){
if(executorService.isTerminated()){
System.out.println("over");
break;
}
}
}
public static void doSomething() throws InterruptedException{
/**
* 每个操作最多两个线程同时进行
*/
System.out.println(Thread.currentThread().getName()+" try to get semaphore.");
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+" is doing something.");
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName()+" release semaphore.");
semaphore.release();
}
}
在上面的例子中,同一时刻只有两个线程在操作某种资源和进行某个动作(doSomething)。
4. 交换器
使用场景:用于两个线程之间交换数据
例子代码:
public class Demo{
public static void main(String [] args){
Exchanger exchanger=new Exchanger();
String content1="content1";
String content2="content2";
ExecutorService es=Executors.newFixedThreadPool(2);
es.submit(new ExchangeDataTask(exchanger,content1));
es.submit(new ExchangeDataTask(exchanger,content2));
es.shutdown();
}
}
class ExchangeDataTask implements Runnable{
private Exchanger exchanger;
private V data;
public ExchangeDataTask(Exchanger exchanger,V data){
this.exchanger=exchanger;
this.data=data;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"交换之前的数据:" + data);
V newData = exchanger.exchange(data);
System.out.println(Thread.currentThread().getName()+"交换之后的数据:" + newData);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}

本文介绍了Java并发编程中常用的几个工具类,希望大家仔细理解。能在合适的场景中使用起来。

java 线程合并结果 java线程并发工具类_java 线程合并结果