Java面試之多執行緒&併發篇(2)

码路编程發表於2024-11-12

前言

本來想著給自己放鬆一下,刷刷部落格,突然被幾道面試題難倒!Thread 類中的start() 和 run() 方法有什麼區別?為什麼wait, notify 和 notifyAll這些方法不在thread類裡面?為什麼wait和notify方法要在同步塊中呼叫?Java中interrupted 和 isInterruptedd方法的區別?ava中synchronized 和 ReentrantLock 有什麼不同?似乎有點模糊了,那就大概看一下面試題吧。好記性不如爛鍵盤

*** 12萬字的java面試題整理 ***

Thread 類中的start() 和 run() 方法有什麼區別?

start()方法被用來啟動新建立的執行緒,而且start()內部呼叫了run()方法,這和直接呼叫run()方法的效果不一樣。當你呼叫run()方法的時候,只會是在原來的執行緒中呼叫,沒有新的執行緒啟動,start()方法才會啟動新執行緒。

為什麼wait, notify 和 notifyAll這些方法不在thread類裡面?

明顯的原因是JAVA提供的鎖是物件級的而不是執行緒級的,每個物件都有鎖,透過執行緒獲得。如果執行緒需要等待某些鎖那麼呼叫物件中的wait()方法就有意義了。如果wait()方法定義在Thread類中,執行緒正在等待的是哪個鎖就不明顯了。簡單的說,由於wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類中因為鎖屬於物件。

為什麼wait和notify方法要在同步塊中呼叫?

  1. 只有在呼叫執行緒擁有某個物件的獨佔鎖時,才能夠呼叫該物件的wait(),notify()和notifyAll()方法。
  2. 如果你不這麼做,你的程式碼會丟擲IllegalMonitorStateException異常。
  3. 還有一個原因是為了避免wait和notify之間產生競態條件。

wait()方法強制當前執行緒釋放物件鎖。這意味著在呼叫某物件的wait()方法之前,當前執行緒必須已經獲得該物件的鎖。因此,執行緒必須在某個物件的同步方法或同步程式碼塊中才能呼叫該物件的wait()方法。

在呼叫物件的notify()和notifyAll()方法之前,呼叫執行緒必須已經得到該物件的鎖。因此,必須在某個物件的同步方法或同步程式碼塊中才能呼叫該物件的notify()或notifyAll()方法。

呼叫wait()方法的原因通常是,呼叫執行緒希望某個特殊的狀態(或變數)被設定之後再繼續執行。呼叫notify()或notifyAll()方法的原因通常是,呼叫執行緒希望告訴其他等待中的執行緒:"特殊狀態已經被設定"。這個狀態作為執行緒間通訊的通道,它必須是一個可變的共享狀態(或變數)。

Java中interrupted 和 isInterruptedd方法的區別?

interrupted() 和 isInterrupted()的主要區別是前者會將中斷狀態清除而後者不會。Java多執行緒的中斷機制是用內部標識來實現的,呼叫Thread.interrupt()來中斷一個執行緒就會設定中斷標識為true。

當中斷執行緒呼叫靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。而非靜態方法isInterrupted()用來查詢其它執行緒的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何丟擲InterruptedException異常的方法都會將中斷狀態清零。無論如何,一個執行緒的中斷狀態有有可能被其它執行緒呼叫中斷來改變。

Java中synchronized 和 ReentrantLock 有什麼不同?

相似點:
這兩種同步方式有很多相似之處,它們都是加鎖方式同步,而且都是阻塞式的同步,也就是說當如果一個執行緒獲得了物件鎖,進入了同步塊,其他訪問該同步塊的執行緒都必須阻塞在同步塊外面等待,而進行執行緒阻塞和喚醒的代價是比較高的.

區別:
這兩種方式最大區別就是對於Synchronized來說,它是java語言的關鍵字,是原生語法層面的互斥,需要jvm實現。而ReentrantLock它是JDK 1.5之後提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally語句塊來完成。

Synchronized進過編譯,會在同步塊的前後分別形成monitorenter和monitorexit這個兩個位元組碼指令。在執行monitorenter指令時,首先要嘗試獲取物件鎖。如果這個物件沒被鎖定,或者當前執行緒已經擁有了那個物件鎖,把鎖的計算器加1,相應的,在執行monitorexit指令時會將鎖計算器就減1,當計算器為0時,鎖就被釋放了。如果獲取物件鎖失敗,那當前執行緒就要阻塞,直到物件鎖被另一個執行緒釋放為止。

由於ReentrantLock是java.util.concurrent包下提供的一套互斥鎖,相比Synchronized,ReentrantLock類提供了一些高階功能,主要有以下3項:
1.等待可中斷,持有鎖的執行緒長期不釋放的時候,正在等待的執行緒可以選擇放棄等待,這相當於Synchronized來說可以避免出現死鎖的情況。
2.公平鎖,多個執行緒等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock預設的建構函式是建立的非公平鎖,可以透過引數true設為公平鎖,但公平鎖表現的效能不是很好。
3.鎖繫結多個條件,一個ReentrantLock物件可以同時繫結對個物件。

相關文章