java 多執行緒 併發 面試

idaretobe發表於2015-01-13


多執行緒

  1. java中有幾種方法可以實現一個執行緒?
  2. 如何停止一個正在執行的執行緒?
  3. notify()和notifyAll()有什麼區別?
  4. sleep()和 wait()有什麼區別?
  5. 什麼是Daemon執行緒?它有什麼意義?
  6. java如何實現多執行緒之間的通訊和協作?

  1. 什麼是可重入鎖(ReentrantLock)?
  2. 當一個執行緒進入某個物件的一個synchronized的例項方法後,其它執行緒是否可進入此物件的其它方法?
  3. synchronized和java.util.concurrent.locks.Lock的異同?
  4. 樂觀鎖和悲觀鎖的理解及如何實現,有哪些實現方式?

併發框架

  1. SynchronizedMap和ConcurrentHashMap有什麼區別?
  2. CopyOnWriteArrayList可以用於什麼應用場景?

執行緒安全

  1. 什麼叫執行緒安全?servlet是執行緒安全嗎?
  2. 同步有幾種實現方法?
  3. volatile有什麼用?能否用一句話說明下volatile的應用場景?
  4. 請說明下java的記憶體模型及其工作流程。
  5. 為什麼程式碼會重排序?

併發容器和框架

  1. 如何讓一段程式併發的執行,並最終彙總結果?
  2. 如何合理的配置java執行緒池?如CPU密集型的任務,基本執行緒池應該配置多大?IO密集型的任務,基本執行緒池應該配置多大?用有界佇列好還是無界佇列好?任務非常多的時候,使用什麼阻塞佇列能獲取最好的吞吐量?
  3. 如何使用阻塞佇列實現一個生產者和消費者模型?請寫程式碼。
  4. 多讀少寫的場景應該使用哪個併發容器,為什麼使用它?比如你做了一個搜尋引擎,搜尋引擎每次搜尋前需要判斷搜尋關鍵詞是否在黑名單裡,黑名單每天更新一次。

Java中的鎖

  1. 如何實現樂觀鎖(CAS)?如何避免ABA問題?
  2. 讀寫鎖可以用於什麼應用場景?
  3. 什麼時候應該使用可重入鎖?
  4. 什麼場景下可以使用volatile替換synchronized?

併發工具

  1. 如何實現一個流控程式,用於控制請求的呼叫次數?

答案

可以閱讀以下參考資料,知道答案後可以在回覆中交流

http://www.cnblogs.com/dolphin0520/category/602384.html
補充教程:
  1. Java併發性和多執行緒介紹
  2. 多執行緒的優點
  3. 多執行緒的代價
  4. 如何建立並執行java執行緒
  5. 競態條件與臨界區
  6. 執行緒安全與共享資源
  7. 執行緒安全及不可變性
  8. JAVA同步塊
  9. 執行緒通訊
  10. 死鎖
  11. 避免死鎖
  12. 飢餓和公平
  13. 巢狀管程鎖死
  14. Slipped Conditions
  15. Java中的鎖
  16. Java中的讀/寫鎖
  17. 重入鎖死
  18. 訊號量
  19. 阻塞佇列
  20. 執行緒池
  21. 剖析同步器

1、java 高併發包所採用的幾個機制(CAS,volatile,抽象佇列同步)

   CAS(樂觀操作),jdk5以前採用synchronized,對共享區域進行同步操作,synchronized是重的操作,在高併發情況下,會引起執行緒頻繁切換;而CAS是一種樂觀鎖機制,compare and swap,不加鎖,而是假設沒有衝突去完成,若有衝突會重試(非阻塞)。compare&swap是原子操作,基於CPU的原語操作。

   volatile(變數的可見性),VM阻止volatile變數的值放入處理器的暫存器,在寫入值以後會被從處理器的cache中flush掉,寫到記憶體中去,這樣其他執行緒都可以立刻看到該變數的變化。

  AQS,抽象佇列同步器(原子性操作狀態同步位、有序佇列、阻塞喚醒程式)

     獲取鎖:首先判斷當前狀態是否允許獲取鎖,如果是就獲取鎖,否則就阻塞操作或者獲取失敗,也就是說如果是獨佔鎖就可能阻塞,如果是共享鎖就可能失敗。另外如果是阻塞執行緒,那麼執行緒就需要進入阻塞佇列。當狀態位允許獲取鎖時就修改狀態,並且如果進了佇列就從佇列中移除。

    釋放鎖:這個過程就是修改狀態位,如果有執行緒因為狀態位阻塞的話就喚醒佇列中的一個或者更多執行緒。

2、鎖相關:

Semaphere,控制某資源同時被訪問的個數的類

    在許可可用前會阻塞每一個 acquire(),然後再獲取該許可。每個 release() 新增一個許可,從而可能釋放一個正在阻塞的獲取者

    Semaphore position=new Semaphore(2);  

    position.acquire(); //阻塞,直到等待的當前的個數少於2個

    position.release()

CountDownLatch,一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。 

      CountDownLatch end = new CountDownLatch(10);  

      end.countDown();  10次

      end.wait阻塞直到end.countDown();  10次

CyclicBarrier,一個同步輔助類,它允許一組執行緒互相等待,直到到達某個公共屏障點 

      CyclicBarrier barrier = new CyclicBarrier(3);barrier.await()//三次

 

ReentrantLock,控制併發資源,功能上等同於synchronize

     ReentrantLock  lock=new ReentrantLock();

      lock.lock();

      lock.unlock  

Condition,在同一個鎖的情況下,根據不同的情況執行等待和喚醒動作,類似於object.wait、notify操作

     Condition cond=ReentrantLock.newCondition();

     cond.await();

     cond.signal();  

ReentrantReadWriteLock,

讀寫鎖--ReadWriteLock介面及其實現類ReentrantReadWriteLock

ReentrantReadWriteLock中定義了2個內部 類, ReentrantReadWriteLock.ReadLock和ReentrantReadWriteLock.WriteLock, 分別用來代表讀取鎖和寫入鎖. ReentrantReadWriteLock物件提供了readLock()和writeLock()方法, 用於獲取讀取鎖和寫入鎖.

  • 讀取鎖允許多個reader執行緒同時持有, 而寫入鎖最多隻能有一個writter執行緒持有.
  • 讀寫鎖的使用場合: 讀取共享資料的頻率遠大於修改共享資料的頻率. 在上述場合下, 使用讀寫鎖控制共享資源的訪問, 可以提高併發效能.
  • 如果一個執行緒已經持有了寫入鎖, 則可以再持有讀寫鎖. 相反, 如果一個執行緒已經持有了讀取鎖, 則在釋放該讀取鎖之前, 不能再持有寫入鎖.
  • 在多執行緒環境中,讀鎖和寫鎖是相互排斥的,一個lock不可能同時擁有讀鎖和寫鎖. 

3、併發容器:

1)非併發包中的集合容器,

Collection
|---List
|--ArryList,Vector(thread safe),Linklist
|--Set
|---HashSet
|---Map
         |----HashMap(陣列,每個元素是hashentry,利用雜湊,定位物件儲存的位置index,便於快速定位物件;hash衝突的解決採用連結串列結構儲存)

|----HashTable(thread safe) 

2)併發包中的執行緒安全的集合容器

  ConcurrentMap( 執行緒安全的hashMap),預設16個segment的陣列,每個segment中實現就是hashMap了,通過hash定位segment。put操作是在segment層上加鎖的,這樣可以減少併發的衝突;讀操作大多數情況下無鎖操作(僅僅找到的hashentry對應的物件為null時,有鎖操作)。

  CopyOnWriteArrayList,執行緒安全,讀操作時無鎖的ArrayList;在寫時,copy一個ArrayList,寫完成後,指標指向新的物件。

  CopyOnWriteArraySet,基於CopyOnWriteArrayList實現。

  ArrayBlockQueue,基於陣列,FIFO,執行緒安全的集合類,容量可以限制。

4、 執行緒中斷

interrupt()不會中斷正在執行的執行緒,只是將執行緒的標誌位設定成true。但是如果執行緒在呼叫sleep(),join(),wait()方法時執行緒被中斷,則這些方法會丟擲InterruptedException,在catch塊中捕獲到這個異常時,執行緒的中斷標誌位已經被設定成false了,因此在此catch塊中呼叫t.isInterrupted(),Thread.interrupted()始終都為false, 而t.isInterrupted與Thread.interrupted()的區別是API中已經說明很明顯了,Thread.interrupted()假如當前的中斷標誌為true,則調完後會將中斷標誌位設定成false 。


相關文章