一、CountdownLatch
- 允许一个或多个线程等待直到在其他线程中执行的一组操作完成。
示例代码:
public class CountdownLatchTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3);
//开启3个子线程
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
System.out.println("线程" + Thread.currentThread().getName() + "正准备接受命令");
//3个线程阻塞,等cdOrder.countDown()减到0,然后再继续执行
cdOrder.await();
System.out.println("线程" + Thread.currentThread().getName() + "已接受命令");
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果");
//3个线程依次减一
cdAnswer.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.submit(runnable);
}
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令");
cdOrder.countDown();
System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果");
//阻塞,等cdAnswer.countDown()减到0
cdAnswer.await();
System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果");
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}
- a CountDownLatch用给定的计数初始化。 await方法阻塞,直到由于countDown()方法的调用而导致当前计数达到零,之后所有等待线程被释放, 并且任何后续的await 调用立即返回。 这是一个一次性的现象 - 计数无法重置。 如果您需要重置计数的版本,请考虑使用CyclicBarrier 。
二、CyclicBarrier
允许一组线程全部等待彼此达到共同屏障点。可以循环执行
示例代码:
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.submit(runnable);
}
service.shutdown();
}
}
三、Exchanger交换器
- 线程可以在成对内 配对和交换元素的同步点。 每个线程在输入exchange方法时提供一些对象,与合作者线程匹配,并在返回时接收其合作伙伴的对象。
- 交换器可以被视为一个的双向形式SynchronousQueue 。交换器在诸如遗传算法和管道设计的应用中可能是有用的。
示例代码:
public class ExchangerTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
service.submit(new Runnable(){
public void run() {
try {
String data1 = "zxx";
System.out.println("线程" + Thread.currentThread().getName() +"正在把数据" + data1 +"换出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() +"换回的数据为" + data2);
}catch(Exception e){
}
}
});
service.submit(new Runnable(){
public void run() {
try {
String data1 = "lhm";
System.out.println("线程" + Thread.currentThread().getName() + "正在把数据" + data1 +"换出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为" + data2);
}catch(Exception e){
}
}
});
}
}
四、Semaphore 信号灯
- 互斥是同时只能一个进行操作,与互斥不同,信号灯允许多个线程同时进行操作
- 信号量通常用于限制线程数,而不是访问某些(物理或逻辑)资源。 例如,这是一个使用信号量来控制对一个项目池的访问的类
示例代码:
public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
Semaphore sp = new Semaphore(3);//指定信号灯数量
for (int i = 0; i <10 ; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
sp.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"正在运行,当前有"+(3-sp.availablePermits())+"个在并行");
try {
Thread.sleep((long)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"即将离开。");
sp.release();
System.out.println("线程"+Thread.currentThread().getName()+"已经离开,还有"+(3-sp.availablePermits())+"个线程在并行");
}
};
service.execute(runnable);
}
service.shutdown();
}
}