JUC之tools面經整理

目錄結構:

tools目錄

一、CountDownLatch

閉鎖,一種非常簡單、但很常用的同步輔助類。

問題一:CountDownLatch的作用是什么?

作用:是在完成一組正在其他線程中執行的操作之前,允許一個或多個線程一直阻塞。

問題二:CountDownLatch的原理是什么?

原理:基于 AQS 的共享模式的使用。CountDownLatch在多線程并發編程中充當一個計時器的功能,并且維護一個count的變量,并且其操作都是原子操作,該類主要通過countDown()和await()兩個方法實現功能的,首先通過建立CountDownLatch對象,并且傳入參數即為count初始值。如果一個線程調用了await()方法,那么這個線程便進入阻塞狀態,并進入阻塞隊列。如果一個線程調用了countDown()方法,則會使count-1;當count的值為0時,這時候阻塞隊列中調用await()方法的線程便會逐個被喚醒,從而進入后續的操作。比如下面的例子就是有兩個操作,一個是讀操作一個是寫操作,現在規定必須進行完寫操作才能進行讀操作。所以當最開始調用讀操作時,需要用await()方法使其阻塞,當寫操作結束時,則需要使count等于0。因此count的初始值可以定為寫操作的記錄數,這樣便可以使得進行完寫操作,然后進行讀操作。

問題三:CountDownLatch的步驟

1、首先是創建實例 CountDownLatch countDown = new CountDownLatch(2)

2、需要同步的線程執行完之后,計數-1; countDown.countDown()

3、需要等待其他線程執行完畢之后,再運行的線程,調用 countDown.await()實現阻塞同步

舉例:

例1未使用 CountDownLatch

這段代碼就是10個線程同時去輸出5000以內的偶數,然后在主線程那里計算執行時間。其實這是計算不了那10個線程的執行時間的,因為主線程與這10個線程也是同時執行的,可能那10個線程才執行到一半,主線程就已經輸出“耗費時間為x秒”這句話了。所有要想計算這10個線程執行的時間,就得讓主線程先等待,等10個分線程都執行完了才能執行主線程。這就要用到閉鎖。看如何使用:

例1使用?CountDownLatch??

二、CyclicBarrier

一種可重置的多路同步點,在某些并發編程場景很有用。

問題四:CyclicBarrier的作用

作用:跟CountDownLatch相反,CyclicBarrier設置一個屏障,當要求個數的線程到齊了才能執行,之前到的會一直阻塞在這。即允許一組線程互相等待,直到到達某個公共的屏障點(common barrier point)。

在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時CyclicBarrier很有用,因為該barrier在釋放等待線程后可以重用,所以稱它為循環的barrier

問題五:CyclicBarrier的原理

原理:ReentrantLock 和 Condition 的組合使用

舉例:

例2 CyclicBarrier的使用

問題六:CountDownLatch與CyclicBarrier的區別

1、CyclicBarrier的計數器由自己控制;而CountDownLatch的計數器則由使用者來控制

2、在CyclicBarrier中線程調用await方法不僅會將自己阻塞還會將計數器減1,而在CountDownLatch中線程調用await方法只是將自己阻塞而不會減少計數器的值。

3、CountDownLatch只能攔截一輪,而CyclicBarrier可以實現循環攔截。一般來說用CyclicBarrier可以實現CountDownLatch的功能,而反之則不能。



三、Semaphore

信號量是一類經典的同步工具。信號量通常用來限制線程可以同時訪問的(物理或邏輯)資源數量。

在資源有多個的時候,可以用Semaphore來進行同步。

問題六:Semaphore?的原理

原理:AQS中的Shared相關,如tryAcquireShared()、tryReleaseShared()等方法。通過getState來判斷是否可以獲取資源

使用場景:比如說,又到了十一假期,買票是重點,必須圈起來。在購票大廳里,有5個售票窗口,也就是說同一時刻可以服務5個人。要實現這種業務需求,用synchronized顯然不合適。

查看Java并發工具,發現有一個Semaphore類,天生就是處理這種情況的。

舉例:

例3- Semaphore的使用


四、Phaser

可重用的同步屏障,類似CyclicBarrier和CountDownLatch,但使用上更為靈活

使用場景:非常適用于在多線程環境下同步協調分階段計算任務(Fork/join框架的子任務之間需同步時,優先使用Phaser)


五、Executors

提供了一系列工廠方法用于創建線程池(四種),返回的線程池都實現了ExecutorService接口。


六、Exchanger

允許兩個線程在某個匯合點交換對象,在某些管道設計時比較有用。

Exchanger提供了一個同步點,在這個同步點,一對線程可以交換數據。每個線程通過Exchanger()方法的入口提供數據給他的伙伴線程,并接收他的伙伴線程提供的數據并返回。當兩個線程通過Exchaner交換了對象,這個交換對于兩個線程來說都是安全的。

Exchanger可以認為是SynchronousQueue的雙向形式,在運用到遺傳算法和管道設計的應用中比較有用

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。