Java Semaphore、CyclicBarrier、CountDownLatch

問:如何控制某個方法被并發(fā)訪問的個數(shù)?

答:可以使用 Semaphore,其有兩個核心方法如下:

  • semaphore.acquire():用來請求一個信號量,該方法使信號量個數(shù)減 1;一旦沒有可使用的信號量,即信號量個數(shù)變?yōu)樨摂?shù)時,再次調(diào)用該方法請求時就會阻塞,直到其他線程釋放了信號量。

  • semaphore.release():用來釋放一個信號量,該方法使信號量個數(shù)加 1。

所以本題最簡單的實現(xiàn)方案代碼如下(同時最多可以 5 個并發(fā)訪問):

public class SemaphoreTest {  
    private Semaphore mSemaphore = new Semaphore(5);  

    public void testRun() {  
        for(int i=0; i< 20; i++){  
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    test();  
                }  
            }).start();  
        }  
    }  

    private void test(){  
        try {  
            mSemaphore.acquire();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println(Thread.currentThread().getName() + " enter...");  
        try {  
            Thread.sleep(100);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println(Thread.currentThread().getName() + " exit...");  
        mSemaphore.release();  
    }  
} 

輸出如下:

Thread-1 enter...
Thread-2 enter...
Thread-3 enter...
Thread-4 enter...
Thread-5 enter...
Thread-1 exit...
Thread-6 enter...
Thread-2 exit...
Thread-7 enter...
Thread-3 exit...
Thread-8 enter...
Thread-4 exit...
Thread-9 enter...
Thread-5 exit...
Thread-10 enter...
Thread-7 exit...
Thread-6 exit...
Thread-11 enter...
Thread-12 enter...
Thread-8 exit...
Thread-13 enter...
Thread-10 exit...
Thread-14 enter...
Thread-9 exit...
Thread-15 enter...
Thread-11 exit...
Thread-12 exit...
Thread-16 enter...
Thread-17 enter...
Thread-15 exit...
Thread-18 enter...
Thread-14 exit...
Thread-19 enter...
Thread-13 exit...
Thread-20 enter...
Thread-16 exit...
Thread-19 exit...
Thread-17 exit...
Thread-18 exit...
Thread-20 exit...
問:簡單說說 Java 中 CyclicBarrier 和 CountDownLatch 有什么不同?

答:CountDownLatch 和 CyclicBarrier 都能夠?qū)崿F(xiàn)線程之間的等待,只不過它們側(cè)重點不同。

  • CountDownLatch 一般用于某個線程 A 等待若干個其他線程執(zhí)行完任務(wù)之后,它才執(zhí)行。

  • CyclicBarrier 一般用于一組線程互相等待至某個狀態(tài),然后這一組線程再同時執(zhí)行。

  • 此外,CountDownLatch 是不能夠重用的,而 CyclicBarrier 是可以重用的。

如下是 CountDownLatch 使用樣例:

public class Test {
     public static void main(String[] args) {   
         final CountDownLatch latch = new CountDownLatch(2);

         new Thread(){
             public void run() {
                 try {
                     System.out.println("子線程"+Thread.currentThread().getName()+"正在執(zhí)行");
                    Thread.sleep(3000);
                    System.out.println("子線程"+Thread.currentThread().getName()+"執(zhí)行完畢");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             };
         }.start();

         new Thread(){
             public void run() {
                 try {
                     System.out.println("子線程"+Thread.currentThread().getName()+"正在執(zhí)行");
                     Thread.sleep(3000);
                     System.out.println("子線程"+Thread.currentThread().getName()+"執(zhí)行完畢");
                     latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             };
         }.start();

         try {
             System.out.println("等待2個子線程執(zhí)行完畢...");
            latch.await();
            System.out.println("2個子線程已經(jīng)執(zhí)行完畢");
            System.out.println("繼續(xù)執(zhí)行主線程");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
     }
}

如下是 CyclicBarrier 使用樣例:

public class Test {
    public static void main(String[] args) {
        int N = 4;

        CyclicBarrier barrier  = new CyclicBarrier(N,new Runnable() {
            @Override
            public void run() {
                System.out.println("當前線程"+Thread.currentThread().getName());   
            }
        });

        for(int i=0;i<N;i++) {
            new Writer(barrier).start();
        }
    }

    static class Writer extends Thread{
        private CyclicBarrier cyclicBarrier;

        public Writer(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            System.out.println("線程"+Thread.currentThread().getName()+"正在寫入數(shù)據(jù)...");
            try {
                Thread.sleep(5000);      //以睡眠來模擬寫入數(shù)據(jù)操作
                System.out.println("線程"+Thread.currentThread().getName()+"寫入數(shù)據(jù)完畢,等待其他線程寫入完畢");
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch(BrokenBarrierException e){
                e.printStackTrace();
            }
            System.out.println("所有線程寫入完畢,繼續(xù)處理其他任務(wù)...");
        }
    }
}

本文參考自 Semaphore、CyclicBarrier、CountDownLatch 神器相關(guān)的面試題解析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容