Java提供的synchronized关键字对临界区进行线程同步访问。由于基于synchronized很难
正确编写同步代码,并发工具类提供了高级的同步器。倒计时门闩(countdown latch)、同步屏
障(cyclic barrier)、交换器(exchanger)、信号量(semaphore)以及phaser同步器。下面主要
介绍倒计时门闩和同步屏障。
倒计时门闩会导致一条或多条线程在“门口”一直等待,直到另一条线程打开这扇门,线程
才得以继续运行。他是由一个计数变量和两个操作组成的,这两个操作分别是“导致一条线程等待直到
计数变为0”以及“递减计数变量”。
实现类:java.util.concurrent.CountDownLatch
以下代码是用倒计时门闩实现的一个是所有线程同时执行同时结束之后,才能继续执行主线程:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
final static int NTHREADS = 3;
public static void main(String[] args) {
final CountDownLatch startSignal = new CountDownLatch(1);
final CountDownLatch doneSignal = new CountDownLatch(NTHREADS);
Runnable r = new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "进入等待");
startSignal.await();
System.out.println(Thread.currentThread().getName() + "开始执行任务");
Thread.sleep(200);
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
ExecutorService es = Executors.newFixedThreadPool(NTHREADS);
for (int i = 0; i
es.execute(r);
}
try {
Thread.sleep(1000);
startSignal.countDown();
System.out.println(Thread.currentThread().getName() + "进入等待");
doneSignal.await();
System.out.println(Thread.currentThread().getName() + "开始执行");
es.shutdownNow();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
下面讲解同步屏障:
若有多条线程,他们到达屏障时将会被阻塞,只有当所有线程都到达屏障时才能打开屏障,
所有线程同时执行,若有这样的需求可以使用同步屏障。此外,当屏障打开的同时还能指定执行的任务。
// 创建同步屏障对象,并制定需要等待的线程个数 和 打开屏障时需要执行的任务
CyclicBarrier barrier = new CyclicBarrier(3,new Runnable(){
public void run(){
//当所有线程准备完毕后触发此任务
}
});
// 启动三条线程
for( int i=0; i<3; i++ ){
new Thread( new Runnable(){
public void run(){
// 等待,(每执行一次barrier.await,同步屏障数量-1,直到为0时,打开屏障)
barrier.await();
// 任务
任务代码……
}
} ).start();
}
倒计时门闩 与 同步屏障 的区别 倒计时门闩只会阻塞一条线程,目的是为了让该条任务线程满足条件后执行;
而同步屏障会阻塞所有线程,目的是为了让所有线程同时执行