前言
本來想著給自己放鬆一下,刷刷部落格,突然被幾道面試題難倒!說說CyclicBarrier和CountDownLatch的區別?什麼是AQS?瞭解Semaphore嗎?什麼是Callable和Future?什麼是阻塞佇列?阻塞佇列的實現原理是什麼?如何使用阻塞佇列來實現生產者-消費者模型?似乎有點模糊了,那就大概看一下面試題吧。好記性不如爛鍵盤
*** 12萬字的java面試題整理 ***
*** java核心面試知識整理 ***
*** Java高頻面試講解影片(知識涵蓋齊全) ***
說說CyclicBarrier和CountDownLatch的區別?
兩個看上去有點像的類,都在java.util.concurrent下,都可以用來表示程式碼執行到某個點上,二者的區別在於:
(1)CyclicBarrier的某個執行緒執行到某個點上之後,該執行緒即停止執行,直到所有的執行緒都到達了這個點,所有執行緒才重新執行;CountDownLatch則不是,某執行緒執行到某個點上之後,只是給某個數值-1而已,該執行緒繼續執行
(2)CyclicBarrier只能喚起一個任務,CountDownLatch可以喚起多個任務
(3)CyclicBarrier可重用,CountDownLatch不可重用,計數值為0該CountDownLatch就不可再用了
什麼是AQS?
簡單說一下AQS,AQS全稱為AbstractQueuedSychronizer,翻譯過來應該是抽象佇列同步器。
如果說java.util.concurrent的基礎是CAS的話,那麼AQS就是整個Java併發包的核心了,ReentrantLock、CountDownLatch、Semaphore等等都用到了它。AQS實際上以雙向佇列的形式連線所有的Entry,比方說ReentrantLock,所有等待的執行緒都被放在一個Entry中並連成雙向佇列,前面一個執行緒使用ReentrantLock好了,則雙向佇列實際上的第一個Entry開始執行。
AQS定義了對雙向佇列所有的操作,而只開放了tryLock和tryRelease方法給開發者使用,開發者可以根據自己的實現重寫tryLock和tryRelease方法,以實現自己的併發功能。
瞭解Semaphore嗎?
semaphore就是一個訊號量,它的作用是限制某段程式碼塊的併發數。Semaphore有一個建構函式,可以傳入一個int型整數n,表示某段程式碼最多隻有n個執行緒可以訪問,如果超出了n,那麼請等待,等到某個執行緒執行完畢這段程式碼塊,下一個執行緒再進入。由此可以看出如果Semaphore建構函式中傳入的int型整數n=1,相當於變成了一個synchronized了。
什麼是Callable和Future?
Callable介面類似於Runnable,從名字就可以看出來了,但是Runnable不會返回結果,並且無法丟擲返回結果的異常,而Callable功能更強大一些,被執行緒執行後,可以返回值,這個返回值可以被Future拿到,也就是說,Future可以拿到非同步執行任務的返回值。可以認為是帶有回撥的Runnable。
Future介面表示非同步任務,是還沒有完成的任務給出的未來結果。所以說Callable用於產生結果,Future用於獲取結果。
什麼是阻塞佇列?阻塞佇列的實現原理是什麼?如何使用阻塞佇列來實現生產者-消費者模型?
阻塞佇列(BlockingQueue)是一個支援兩個附加操作的佇列。
這兩個附加的操作是:在佇列為空時,獲取元素的執行緒會等待佇列變為非空。當佇列滿時,儲存元素的執行緒會等待佇列可用。
阻塞佇列常用於生產者和消費者的場景,生產者是往佇列裡新增元素的執行緒,消費者是從佇列裡拿元素的執行緒。阻塞佇列就是生產者存放元素的容器,而消費者也只從容器裡拿元素。
JDK7提供了7個阻塞佇列。分別是:
- ArrayBlockingQueue :一個由陣列結構組成的有界阻塞佇列。
- LinkedBlockingQueue :一個由連結串列結構組成的有界阻塞佇列。
- PriorityBlockingQueue :一個支援優先順序排序的無界阻塞佇列。
- DelayQueue:一個使用優先順序佇列實現的無界阻塞佇列。
- SynchronousQueue:一個不儲存元素的阻塞佇列。
- LinkedTransferQueue:一個由連結串列結構組成的無界阻塞佇列。
- LinkedBlockingDeque:一個由連結串列結構組成的雙向阻塞佇列。
Java 5之前實現同步存取時,可以使用普通的一個集合,然後在使用執行緒的協作和執行緒同步可以實現生產者,消費者模式,主要的技術就是用好,wait ,notify,notifyAll,sychronized這些關鍵字。而在java 5之後,可以使用阻塞佇列來實現,此方式大大簡少了程式碼量,使得多執行緒程式設計更加容易,安全方面也有保障。
BlockingQueue介面是Queue的子介面,它的主要用途並不是作為容器,而是作為執行緒同步的的工具,因此他具有一個很明顯的特性,當生產者執行緒試圖向BlockingQueue放入元素時,如果佇列已滿,則執行緒被阻塞,當消費者執行緒試圖從中取出一個元素時,如果佇列為空,則該執行緒會被阻塞,正是因為它所具有這個特性,所以在程式中多個執行緒交替向BlockingQueue中放入元素,取出元
素,它可以很好的控制執行緒之間的通訊。
阻塞佇列使用最經典的場景就是socket客戶端資料的讀取和解析,讀取資料的執行緒不斷將資料放入佇列,然後解析執行緒不斷從佇列取資料解析。