java併發包原理及使用場景
阿新 • • 發佈:2018-12-16
java併發包下有很多內建的處理執行緒安全問題工具類,在集合中就有2種執行緒同步的類,比如:Vector較ArrayList執行緒安全,但是效率較低,同樣的還有Hashtable和HashMap,在實際專案中常用ArrayList與HashMap,因為前者比重,影響執行效率
- 以下是java的幾種併發包下的使用場景
1.CountDownLatch
CountDownLatch 同步器
1.1 原理:
- 執行多個或一個執行緒,等待其他多個或一個執行緒執行完畢,在執行當前執行緒
- java併發包下同步輔助類:定義計數器可以設定個數,每次呼叫countDown() 計數器中的個數就會減1,當計數器的個數等於0的時候,呼叫await方法時,就會執行await方法後面的程式碼,如果計數器個數大於0時,呼叫await時,是不會執行await後面的程式碼
1.2 使用場景:
- 有一個檔案,需要2個執行緒執行讀寫操作,執行完寫的操作才可以讀取內容 實現:使用計數器CountDownLatch,計數器的個數為2,在每個寫的執行緒執行完畢,呼叫countDown方法,在寫的執行緒後面,呼叫計數器的await方法,await方法後面執行讀執行緒,這樣在讀取資料時,可以保證資料的完整性
public class ThreadWrite implements Runnable { private Poeple peo; private Integer count; private CountDownLatch cdl; public ThreadWrite(Poeple peo, Integer count,CountDownLatch cdl) { this.peo = peo; this.count = count; this.cdl = cdl; } @Override public void run() { System.out.println("ThreadWrite"); if (count == 0) { peo.setName("小明"); peo.setSex("男"); } else if (count == 1) { peo.setName("小紅"); peo.setSex("女"); } cdl.countDown();//每次執行同步器減一 } } public static void main(String[] args) { Poeple peo = new Poeple(); CountDownLatch cdl = new CountDownLatch(2);//建立同步器,執行緒個數為2 new Thread(new ThreadWrite(peo, 1, cdl)).start(); new Thread(new ThreadWrite(peo, 1, cdl)).start(); try { cdl.await();//等待同步器個數為0,執行後續程式碼 new Thread(new ThreadRead(peo)).start(); } catch (InterruptedException e) { e.printStackTrace(); } }
2. CyclicBarrier
CyclicBarrier 迴圈屏障
2.1 原理:
- 執行多個執行緒之間相互等待,執行完畢後在執行執行緒中await後面的程式碼
2.2 使用場景:
- 多個執行緒在執行計算操作,另一個執行緒需要將計算結果相加,建立一個屏障執行緒,等待其他執行緒執行後在執行屏障執行緒
- 多個執行緒中有需要全部執行完,最後執行的程式碼
/** * 寫執行緒 */ public class ThreadWrite implements Runnable { private Poeple peo; private Integer count; private CyclicBarrier cb; public ThreadWrite(Poeple peo, Integer count, CyclicBarrier cb) { this.peo = peo; this.count = count; this.cb = cb; } @Override public void run() { System.out.println("ThreadWrite"); /*迴圈屏障*/ try { cb.await();//等待執行緒數等於,CyclicBarrier中parties個數,執行之前所有等待執行緒await後面的程式碼 System.out.println("迴圈屏障"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } /** * 讀取執行緒 */ public class ThreadRead implements Runnable { private Poeple peo; public ThreadRead(Poeple peo) { this.peo = peo; } @Override public void run() { synchronized (peo) { System.out.println("ThreadRead"); System.out.println(peo.getName()); System.out.println(peo.getSex()); } } } public static void main(String[] args) { CyclicBarrier cb = new CyclicBarrier(4);//迴圈屏障 System.out.println("當前執行緒數"+cb.getParties()); System.out.println("當前執行緒等待數"+cb.getNumberWaiting()); Poeple peo = new Poeple(); int count = 0; new Thread(new ThreadWrite(peo, count,cb)).start(); new Thread(new ThreadWrite(peo, count,cb)).start(); new Thread(new ThreadWrite(peo, count,cb)).start(); new Thread(new ThreadWrite(peo, count,cb)).start(); }
3. Semaphore
Semaphore:訊號量
3.1 原理:
- java併發包下,可以處理一個及以上的執行緒的併發量
3.2 使用場景:
- 一個樓層,有2個入口,一個入口每次只能進1個人,每次可以進2個人,而使用synchronized,只有一個入口,每次只能進1個人,使用訊號量可以提高處理併發的個數
public class ThreadWrite implements Runnable {
private Poeple peo;
private Integer count;
private Semaphore s;
private List<Poeple> peoList;
public ThreadWrite(List<Poeple> peoList, Integer count, Semaphore s) {
this.peoList = peoList;
this.count = count;
this.s = s;
}
@Override
public void run() {
/*訊號量*/
try {
s.acquire();//獲取鎖
System.out.println("ThreadWrite");
Poeple poeple = new Poeple();
poeple.setName("name1");
poeple.setSex("nv");
peoList.add(poeple);
System.out.println(Thread.currentThread().getName() + "=========>" + peoList.size());
s.release();//釋放鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Semaphore s = new Semaphore(3);//訊號量 同時處理三個執行緒
List<Poeple> peo = new ArrayList<>();
int count = 0;
for (int i = 0; i < 20; i++) {
new Thread(new ThreadWrite(peo,count,s),"執行緒1").start();
new Thread(new ThreadWrite(peo,count,s),"執行緒2").start();
new Thread(new ThreadWrite(peo,count,s),"執行緒3").start();
}
}