在JDK的并发包里提供了几个非常有用的工具类。CountDownLatch、CyclicBarrier和Semaphore工具类提供了一种并发流程控制的手段,Exchanger工具类提供了在线程间交换数据的一种手段。
* 闭锁CountDownLatch*
CountDownLatch允许一个或多个线程等待其他线程完成操作。
在JDK1.5之前,我们要达到类似目的,需要使用thread.join()方法,不停检查等待的线程是否存活。而CountDownLatch的出现给我们提供了一种功能更强大、更优雅的方法。
实例一

package com.lipeng.countdownlatch;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
 * CountDownLatchDemo
 * @author LiPeng
 *
 */
public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch latch=new CountDownLatch(2);
        Thread t1=new Thread(new Worker(latch));
        Thread t2=new Thread(new WaitWorker(latch));
        t1.start();
        t2.start();
        try {
            //当前线程等待,直到计数器为0或线程被中断
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("----------all thread exec finish----------");

    }

    static class WaitWorker implements Runnable{
        private CountDownLatch latch;
        public WaitWorker(CountDownLatch latch) {
            super();
            this.latch = latch;
        }

        @Override
        public void run() {
            System.out.println("----------------WaitWorker thread start---------------");
            try {
                //sleep 10s
                TimeUnit.SECONDS.sleep(10);
                //do something
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("---------WaitWorker thread done---------");
            //计数器减一
            latch.countDown();
        }

    }

    static class Worker implements Runnable{
        private CountDownLatch latch;
        public Worker(CountDownLatch latch) {
            super();
            this.latch = latch;
        }

        @Override
        public void run() {
            System.out.println("----------------Worker thread start---------------");
            //do something
            System.out.println("---------Worker thread done---------");
            //计数器减一
            latch.countDown();
        }

    }
}

CountDwonLatch的构造方法结构一个int类型的参数作为计数器的值,如果需要等待N个线程完成工作,那就传入N。
调用countDown方法,计数器值会减1,当计数器值为0时,会唤醒被await阻塞的线程。CountDownLatch同样提供超时时间的await(long time,TimeUnit unit)。如果到了指定的时间,计数器仍然不为0,则同样会唤醒线程。
【备注】:CountDownLatch不能重新初始化或修改其内部计数器的值。


同步屏障CyclicBarrier
CyclicBarrer的作用是让一组线程达到一个屏障(同步点)时被阻塞,直到所有的线程到达此屏障时,才会唤醒被屏障阻塞的所有线程。
实例一:

package com.lipeng.cyclicbarrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
/**
 * CyclicBarrierDemo
 * @author LiPeng
 *
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier barrier=new CyclicBarrier(3);
        Thread t1=new Thread(new Worker1(barrier));
        Thread t2=new Thread(new Worker2(barrier));
        Thread t3=new Thread(new Worker3(barrier));
        t1.start();
        t2.start();
        t3.start();

    }
    static class Worker1 implements Runnable{
        CyclicBarrier barrier;
        public Worker1(CyclicBarrier barrier) {
            super();
            this.barrier = barrier;
        }

        @Override
        public void run() {
            try {
                System.out.println("worker1 is ready and waitting others");
                barrier.await();
                System.out.println("all thread is ready,start do something");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

    }
    static class Worker2 implements Runnable{
        CyclicBarrier barrier;
        public Worker2(CyclicBarrier barrier) {
            super();
            this.barrier = barrier;
        }
        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("worker2 is ready and waitting others");
                barrier.await();
                System.out.println("all thread is ready,start do something");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

    }
    static class Worker3 implements Runnable{
        CyclicBarrier barrier;
        public Worker3(CyclicBarrier barrier) {
            super();
            this.barrier = barrier;
        }
        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(10);
                System.out.println("worker3 is ready and waitting others");
                barrier.await();
                System.out.println("all thread is ready,start do something");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

    }
}

CyclicBarrier默认构造方法CyclicBarrier(int parties),需要传入屏障需要拦截的线程数量。每个线程通过调用await方法告诉CyclicBarrier已经到达屏障,随后被阻塞,直到所有线程到达屏障或线程被中断才被唤醒。
CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parites,Runnable barrierAction),用于在所有线程到达屏障并被唤醒时,优先执行barrierAction。


CyclicBarrier和CounDownLatch的区别
- CountDownLatch的计数器只能使用一次,而CyclicBarrier计数器可以使用reset()方法重置。
- CyclicBarrier还提供获取阻塞线程数量及检测阻塞线程是否被中断等CountDownLatch没有的方法。
【备注】: CountDownLatch的getCount()方法返回还有多少需要调用countDown方法去tryReleaseShared使计数器归0的线程数量。CyclicBarrier的getParties()方法同样返回需要到达屏障的线程数量。


控制并发线程数的Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。
实例一

package com.lipeng.semaphore;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
 * SemaphoreDemo
 * @author LiPeng
 *
 */
public class SemaphoreDemo {

    public static final List<String> MYLIST=new ArrayList<String>();
    public static final Semaphore sem=new Semaphore(2);
    public static final CountDownLatch latch=new CountDownLatch(3);

    public static void main(String[] args) {
        for(int i=0;i<5;++i){
            Thread t1=new Thread(new Work(),"Thread-"+i);
            t1.start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(MYLIST.toString());
    }

    static class Work implements Runnable{
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName()+" try get permition");
                //获取"许可证"
                sem.acquire();
                System.out.println(Thread.currentThread().getName()+" got permition and start work");
                MYLIST.add(Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(5);
                System.out.println(Thread.currentThread().getName()+" done,and release permition");
                //释放"许可证"
                sem.release();
                System.out.println(Thread.currentThread().getName()+" release permition done");
                latch.countDown();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    } 
}

Semaphore(2)表示允许2个线程获取许可证,也就是最大并发数为2。通过调用acquire()方法获取许可证,使用完毕之后调用release()方法归还许可证。
除此之外,Semaphore还提供一些其他方法:
- intavailablePermits():返回此信号量中当前可用的许可证数。
- intgetQueueLength():返回正在等待获取许可证的线程数。
- booleanhasQueuedThreads():是否有线程正在等待获取许可证。
- void reducePermits(int reduction):减少reduction个许可证,是个protected方法。
- Collection getQueuedThreads():返回所有等待获取许可证的线程集合,是个protected方法。


线程间交换数据的Exchanger
Exchanger(交换者)是一个用于线程协作的工具类。可以进行线程间的数据交换。Exchanger提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。线程通过调用Exchanger的exchange()方法来通知Exchanger已经到达同步点,并被阻塞直到另外一个线程也调用exchange()方法到达同步点时,两个线程才可以交换数据。
实例一:

package com.lipeng.exchanger;

import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;

/**
 * ExchangerDemo
 * @author LiPeng
 *
 */
public class ExchangerDemo {

    public static void main(String[] args) {
        Exchanger<String> changer=new Exchanger<String>();
        Thread t1=new Thread(new Worker1(changer,"1a","1b"));
        Thread t2=new Thread(new Worker2(changer,"2a","2b"));
        t1.start();
        t2.start();

    }
}
class Worker1 implements Runnable{

    private Exchanger<String> exchanger;
    private String a;
    private String b;
    public Worker1(Exchanger<String> exchanger, String a, String b) {
        super();
        this.exchanger = exchanger;
        this.a = a;
        this.b = b;
    }

    @Override
    public void run() {
        System.out.println("-----start exec thread 1--------");
        try {
            //等待worker2 调用exchange交换数据
            this.a=exchanger.exchange(this.a);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-----exec thread 1 done--------");
        System.out.println(this.toString());
    }

    @Override
    public String toString() {
        return "Worker1 [exchanger=" + exchanger + ", a=" + a + ", b=" + b
                + "]";
    }


}
class Worker2 implements Runnable{
    private Exchanger<String> exchanger;
    private String a;
    private String b;
    public Worker2(Exchanger<String> exchanger, String a, String b) {
        super();
        this.exchanger = exchanger;
        this.a = a;
        this.b = b;
    }
    @Override
    public void run() {
        System.out.println("-----start exec thread 2--------");
        try {
            //sleep 5s 后调用exchange方法
            TimeUnit.SECONDS.sleep(5);
            this.a=exchanger.exchange(this.a);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-----exec thread 2 done--------");
        System.out.println(this.toString());
    }

    @Override
    public String toString() {
        return "Worker2 [exchanger=" + exchanger + ", a=" + a + ", b=" + b
                + "]";
    }

}