AQS,既AbstractQueuedSynchronizer, 是JUC包實現同步的基礎工具,是一個抽象類。
在AQS中,定義了一個volatile int state變量作爲共享資源,並且內置自旋鎖實現的同步隊列,封裝入隊和出隊的操作,提供獨佔、共享、中斷等特性的方法。
如果線程獲取資源失敗,則進入同步FIFO(先進先出)隊列中等待(入隊);
如果成功獲取資源就執行臨界區代碼。
執行完釋放資源時,通知隊列中的等待線程來獲取資源,然後出隊。
AQS的子類可以定義不停的資源實現不同性質的方法
ReetrantLock
可重入鎖。定義state爲0時可以獲取資源並置爲1.若已獲得資源,state不斷地+1,在釋放資源時state-1,直至爲0
CountDownLatch
CountDownLatch也是juc包中的一個類,類似倒計時計數器,初始時定義了資源總量state=count,調用await()方法則處於等待狀態。countDown()不斷地將state-1,當state=0時才能獲得鎖,所有線程都不會等待。
使用場景:
將主線程阻塞,等異步的多線程全部執行完畢並返回結果後,再繼續執行主線程。
public static List<String> getExecutorService() throws InterruptedException{
System.out.println("開始執行多線程...");
long startTime = System.currentTimeMillis();
List<String> list = new CopyOnWriteArrayList<>();//存放返回結果
CountDownLatch countDownLatch = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
Runnable runnable = new Runnable(){
@Override
public void run() {
try {
Thread.sleep(3000);
list.add(UUID.randomUUID().toString());
System.out.println("當前線程name : "+Thread.currentThread().getName());
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executorService.execute(runnable);
}
countDownLatch.await();
System.out.println("submit總共cost 時間:" + (System.currentTimeMillis()-startTime)/1000 + "秒");
executorService.shutdown();
return list;
}
CountDownLatch是一次性的,state減到0後就釋放鎖,如果再想用就只能重新創建一個,如果希望循環使用,推薦使用CyclicBarrier.
Semaphore
信號量。與CountDownLatch不同的是,同樣也是定義了資源總量state=permits,當state>0時就能獲得鎖,並將state-1,當state=0時只能等待其他線程釋放鎖,當其他線程釋放鎖時state+1,這樣等待的線程又能獲得這個鎖
當Semaphore的permits定義爲1時,就是互斥鎖,當permits>1時就是共享鎖