Java併發包(1):CountDownLatch、CyclicBarrier、Semaphore

1.CountDownLatch
CountDownLatch.wait()會使當前線程阻塞,直到CountDownLatch中的計數器遞減完畢後繼續執行。

public class CountDownLatchDemo {

private final static Logger log = Logger.getLogger(AtomicIntegerCyclicBarrierDemo.class);

public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        new Thread(){
                public void run() {
                                log.info(Thread.currentThread().getName() + " running");
                                latch.countDown();
                };
        }.start();
        new Thread(){
                public void run() {
                        try {
                                log.info(Thread.currentThread().getName() + " running");
                                Thread.sleep(5000);
                                latch.countDown();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                };
        }.start();
        try {
                latch.await();
                log.info("all finished");
        } catch (InterruptedException e) {
                e.printStackTrace();
        }
    }
}

運行日誌:
2019-10-24 09:23:24,069-[HL][17] INFO Thread-0 AtomicIntegerCyclicBarrierDemo - Thread-0 running
2019-10-24 09:23:24,075-[HL][24] INFO Thread-1 AtomicIntegerCyclicBarrierDemo - Thread-1 running
2019-10-24 09:23:29,076-[HL][34] INFO main AtomicIntegerCyclicBarrierDemo - all finished
見第三條09:23:29,主線程一直阻塞直到線程2完成後才繼續向下執行


2.CyclicBarrier
CyclicBarrier可以比做一個阻攔器,當同時阻塞的線程數達到某個個數時,纔會將所有線程放行,這裏結合 同樣是併發包中的AtomicInteger實現了一個案例,AtomicInteger時基於CAS實現的樂觀鎖,也就是說當修改值與預期值不一致時,AtomicInteger會修改失敗並重試,也就是說當我們用多個線程同時累加,在所有線程執行完畢之後,結果是安全的

public class AtomicIntegerCyclicBarrierDemo {

private final static Logger log = Logger.getLogger(AtomicIntegerCyclicBarrierDemo.class);

private final static AtomicInteger count = new AtomicInteger(0);

private final static int THREAD_COUNT = 100;

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT, new Runnable() {
            public void run() {
                log.info(String.format("result = %s", count.get()));
            }
        });
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Task(barrier, count).start();
        }
    }
}

class Task extends Thread {

private CyclicBarrier cyclicBarrier;

private AtomicInteger count;

public Task(CyclicBarrier cyclicBarrier, AtomicInteger count) {
    this.cyclicBarrier = cyclicBarrier;
    this.count = count;
}

@Override
public void run() {
    super.run();
    try {
        count.addAndGet(2);
        cyclicBarrier.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        e.printStackTrace();
    }
}
}

運行日誌:
2019-10-24 09:40:11,961-[HL][22] INFO Thread-99 AtomicIntegerCyclicBarrierDemo - result = 200
CyclicBarrier幫助我們在所有線程執行完之後,進行結果的打印


3.Semaphore
Semaphore用來控制可同時運行的線程數,比如一個案例,我們有一些模型轉換任務,爲了控制計算資源佔用,只允許同時3個線程同時運行,每當一個線程運行完才能空出一個槽位給新的線程運行,下面見代碼

public class SemaphoreDemo {

private final static int THREAD_COUNT = 8 ;

public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(3);
    for(int i = 0; i < THREAD_COUNT ; i++) {
        try {
            Thread.sleep(2000);
            new Task2(i, semaphore).start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}

class Task2 extends Thread{

private final static Logger log = Logger.getLogger(Task2.class);

private int num;

private Semaphore semaphore;

public Task2(int num,Semaphore semaphore){
    this.num = num;
    this.semaphore = semaphore;
}

@Override
public void run() {
    try {
        semaphore.acquire();
        log.info(String.format("task(id = %s) opeater", this.num));
        Thread.sleep(10000);
        log.info(String.format("task(id = %s) finished", this.num));
        semaphore.release();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

運行日誌:
2019-10-24 09:51:49,180-[HL][39] INFO Thread-0 Task2 - task(id = 0) opeater
2019-10-24 09:51:51,150-[HL][39] INFO Thread-1 Task2 - task(id = 1) opeater
2019-10-24 09:51:53,151-[HL][39] INFO Thread-2 Task2 - task(id = 2) opeater
2019-10-24 09:51:59,190-[HL][41] INFO Thread-0 Task2 - task(id = 0) finished
2019-10-24 09:51:59,190-[HL][39] INFO Thread-3 Task2 - task(id = 3) opeater
2019-10-24 09:52:01,151-[HL][41] INFO Thread-1 Task2 - task(id = 1) finished
2019-10-24 09:52:01,152-[HL][39] INFO Thread-4 Task2 - task(id = 4) opeater
2019-10-24 09:52:03,151-[HL][41] INFO Thread-2 Task2 - task(id = 2) finished
2019-10-24 09:52:03,159-[HL][39] INFO Thread-5 Task2 - task(id = 5) opeater

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章