java經常使用的併發工具類

在java1.5中引入了一些很重要的併發工具類好比:CyclicBarrier、Semaphore、countDownLatch、concurrentHashMap和BlockingQueue。今天咱們就來重點聊一聊經常使用的CyclicBarrier、Semaphore、countDownLatch這三個併發工具類。java

CountDownLatch

概念:countDownLatch這個類使一個線程等待其餘線程各自執行完畢後再執行。是經過一個計數器來實現的,計數器的初始值是線程的數量。每當一個線程執行完畢後,計數器的值就-1,當計數器的值爲0時,表示全部線程都執行完畢,而後在閉鎖上等待的線程就能夠恢復工做了。併發

做用:讓一些線程阻塞直到另一些線程完成一些列操做以後才被喚醒,CountDownLatch主要有兩個方法,當一個或者多個線程調用await()方法時候,調用線程會阻塞。其餘線程調用countDown方法會將計數器減1(調用CountDown方法的線程不會阻塞)。當計數器的值變成0時候,因調用await方法被阻塞的線程會被喚醒,繼續執行。工具

//參數count爲計數值
public CountDownLatch(int count) {  };  
//調用await()方法的線程會被掛起,它會等待直到count值爲0才繼續執行
public void await() throws InterruptedException { };   
//和await()相似,只不過等待必定的時間後count值還沒變爲0的話就會繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//將count值減1
public void countDown() { };

場景:放學後5個同窗分別走出教室,每一個同窗走出教室前都要關燈(一個線程表明一個同窗),只有當5名同窗都走完以後門衛纔會把門關掉。難點:因爲線程結束順序是不可預知的,而在這個場景中只有前5個學生線程執行結束後,門衛線程才能執行。ui

public class CountDownLatchDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
              new Thread(()->{
                  System.out.println(Thread.currentThread().getName() + "  關燈走人");
              },String.valueOf(i)).start();
        }

     System.out.println("人走完,門衛最後鎖門");

    }
}

人走完,門衛最後鎖門
0  關燈走人
3  關燈走人
2  關燈走人
1  關燈走人
4  關燈走人

使用CountDownLatch完成操作系統

public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch count = new CountDownLatch(5);
        for (int i = 0; i < 5; i++) {
              new Thread(()->{
                  System.out.println(Thread.currentThread().getName() + "  關燈走人");
                  count.countDown();
              },String.valueOf(i)).start();
        }
        try {
            count.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("人走完,門衛最後鎖門");

    }
}
1  關燈走人
2  關燈走人
0  關燈走人
3  關燈走人
4  關燈走人
人走完,門衛最後鎖門

CyclicBarrier

CyclicBarrier的字面意思是可循環(Cyclic)使用的屏障(Barrier)。它要作的事情是讓一組線程到達一個屏障(也能夠叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,全部被屏障攔截的線程纔會繼續幹活,線程進入屏障經過CyclicBarrier的await()方法。線程

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
  • parties 是參與線程的個數
  • 第二個構造方法有一個 Runnable 參數,這個參數的意思是最後一個到達線程要作的任務
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
  • 線程調用 await() 表示本身已經到達柵欄
  • BrokenBarrierException 表示柵欄已經被破壞,破壞的緣由多是其中一個線程 await() 時被中斷或者超時

舉例:集齊七顆龍珠才能召喚神龍code

public class CyclicBarrierDemo {

    public static void main(String[] args) {
        //第二個參數是一個Runnable接口實現類,只有被cyclicBarrier阻塞的線程達到7個的時候Runnable纔會執行,也就是說傳入的線程只有等規定數量線程被阻塞以後才能執行。
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("成功集齊7龍珠,召喚神龍");
        });
        for (int i = 0; i < 7; i++) {
             final int temp = i;
              new Thread(()->{
                  System.out.println("已經收集第"+(temp+1)+"顆龍珠");
                  try {
                      cyclicBarrier.await();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  System.out.println("龍珠"+temp);
              }).start();
        }

    }
}


已經收集第2顆龍珠
已經收集第1顆龍珠
已經收集第3顆龍珠
已經收集第4顆龍珠
已經收集第5顆龍珠
已經收集第6顆龍珠
已經收集第7顆龍珠
成功集齊7龍珠,召喚神龍
龍珠6
龍珠1
龍珠4
龍珠3
龍珠5
龍珠2
龍珠0

CountDownLatch和CyclicBarrier區別:接口

  1. countDownLatch是一個計數器,線程完成一個記錄一個,計數器遞減,只能只用一次
  2. CyclicBarrier的計數器更像一個閥門,須要全部線程都到達,而後繼續執行,計數器遞增,提供reset功能,能夠屢次使用

Semaphore

信號量主要用於兩個目的,一個是用於共享資源的互斥使用,另外一個是用於併發線程數量的控制資源

相似於操做系統課程裏邊線程同步裏邊的信號量機制。(這個信號量機制但是很強大的喲)get

舉例:多個線程搶佔多個資源,在傳統的synchronized或者lock中適合於多個線程搶佔一個共享資源類,若是要實現多個線程搶佔多個資源類就有點無能爲力。

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);//模擬三個車位
        for (int i = 0; i < 6; i++) {

              new Thread(()->{
                  try {
                      semaphore.acquire();//信號量-1
                      System.out.println(Thread.currentThread().getName()+"  搶到停車場車位");
                      //線程休眠
                      try{ TimeUnit.SECONDS.sleep(3); } catch (Exception e) { e.printStackTrace(); }
                      System.out.println(Thread.currentThread().getName()+"  停車三秒後退出停車場");

                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  } finally {
                      semaphore.release();//信號量+1
                  }


              },String.valueOf(i)).start();

        }
    }
}

0  搶到停車場車位
1  搶到停車場車位
2  搶到停車場車位
0  停車三秒後退出停車場
3  搶到停車場車位
1  停車三秒後退出停車場
2  停車三秒後退出停車場
5  搶到停車場車位
4  搶到停車場車位
3  停車三秒後退出停車場
5  停車三秒後退出停車場
4  停車三秒後退出停車場
相關文章
相關標籤/搜索