CyclicBarrier,CountDownLatch和Semaphore的介绍

125 阅读2分钟

CyclicBarrier,CountDownLatch和Semaphore

CyclicBarrier

CyclicBarrier是制造一个屏障,多个线程共享一个Barrier对象,到达栅栏处的时候(线程运行达到一个状态),使用cyclicBarrier.await()标记,这时候这个线程停下等待其他线程到达栅栏,所有线程都到达之后,CyclicBarrier失效,运行最初设置的那个线程,如下:

CyclicBarrier cyclicBarrier = new CyclicBarrier(count, () -> {
            System.out.println("所有线程到达栅栏处,可以做一些处理");
        });

接着所有线程从await()的地方开始运行。

整个Demo:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

class CyclicBarrierTaskTest implements Runnable {

    private CyclicBarrier cyclicBarrier;

    private int timeout;

    public CyclicBarrierTaskTest(CyclicBarrier cyclicBarrier, int timeout) {
        this.cyclicBarrier = cyclicBarrier;
        this.timeout = timeout;
    }

    @Override
    public void run() {
        TestCyclicBarrier.print("is running...");
        try {
            TimeUnit.SECONDS.sleep(timeout);
            TestCyclicBarrier.print("到达栅栏处,等待其他线程到达");
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

        TestCyclicBarrier.print("所有线程到达栅栏处,继续执行各自线程任务");
    }
}

public class TestCyclicBarrier  {
    public static void print(String str) {
        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
        System.out.println(df.format(new Date()) + " - " + Thread.currentThread().getName() + ": " +str);
    }

    public static void main(String[] args) {
        int count = 5;
        ExecutorService es = Executors.newFixedThreadPool(count);

        CyclicBarrier cyclicBarrier = new CyclicBarrier(count, () -> {
            System.out.println("所有线程到达栅栏处,可以做一些处理");
        });
        for (int i = 0; i < count; i++) {
            es.execute(new CyclicBarrierTaskTest(cyclicBarrier, (i+1)));
        }
    }
}

CountDownLatch

设定一个值,之后每次一个线程运行完之后可以调用countDown方法,让这个值减一,减到0之后回到await()的主线程

Demo:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class TaskTest implements Runnable {

    private CountDownLatch latch;
    private int sleepTime;

    /**
     *
     */
    public TaskTest(int sleepTime, CountDownLatch latch) {
        this.sleepTime = sleepTime;
        this.latch = latch;
    }

    /**
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        try {
            CountDownLatchTest.print(" is running。");
            TimeUnit.MILLISECONDS.sleep(sleepTime);
            CountDownLatchTest.print(" finished。");
            //计数器减减
            latch.countDown();
            System.out.println(latch.getCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

public class CountDownLatchTest {
    public static void main(String[] args) {
        int count = 10;
        final CountDownLatch latch = new CountDownLatch(count);
        ExecutorService es = Executors.newFixedThreadPool(count);
        for (int i = 0; i < count; i++) {
            es.execute(new TaskTest((i + 1) * 1000, latch));
        }

        try {
            CountDownLatchTest.print(" waiting...");
            //主线程等待其它事件发生
            latch.await();
            //其它事件已发生,继续执行主线程
            CountDownLatchTest.print(" continue。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            es.shutdown();
        }
    }

    public static void print(String str){
        SimpleDateFormat dfdate = new SimpleDateFormat("yy.MM.dd:hh:mm:ss:SS");
        System.out.println("[" + dfdate.format(new Date()) + "]" + " " + Thread.currentThread().getName() + ": " + str);
    }

一运行latch.await()就进行阻塞等待latch.getcount()降到0,之后从await()处重启

Semaphore

Semaphore则是,线程通过semaphore.acquire(),请求一个信号量,如果请求不到就等待(因为别人把信号量请求光了),等别人调用semaphore.release()方法释放信号量,就可以去竞争请求了。

Demo:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreTest {
    public static void print(String str) {
        SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss");
        System.out.println(df.format(new Date())+" - "+Thread.currentThread().getName()+": "+str);
    }

    public static void main(String[] args) {
        int threadCount = 10;
        Semaphore semaphore = new Semaphore(5);
        ExecutorService es = Executors.newFixedThreadPool(threadCount);

        for (int i = 0; i < threadCount; i ++) {
            es.submit(new ConsumeResourceTask(semaphore, 1000));
        }
        es.shutdown();
    }
}

class ConsumeResourceTask implements Runnable {

    private Semaphore semaphore;
    private int sleepTime;

    public ConsumeResourceTask(Semaphore semaphore, int sleepTime) {
        this.semaphore = semaphore;
        this.sleepTime = sleepTime;
    }

    @Override
    public void run() {

        try {
            semaphore.acquire();
            SemaphoreTest.print("占用一个资源");
            TimeUnit.MILLISECONDS.sleep(sleepTime);
            SemaphoreTest.print("资源占用结束,释放资源");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }