前言
本來想著給自己放鬆一下,刷刷部落格,突然被幾道面試題難倒!如何停止一個正在執行的執行緒?notify()和notifyAll()有什麼區別?sleep()和wait() 有什麼區別?volatile 是什麼?可以保證有序性嗎?似乎有點模糊了,那就大概看一下面試題吧。好記性不如爛鍵盤
*** 12萬字的java面試題整理 ***
如何停止一個正在執行的執行緒
- 使用退出標誌,使執行緒正常退出,也就是當run方法完成後執行緒終止。
- 使用stop方法強行終止,但是不推薦這個方法,因為stop和suspend及resume一樣都是過期作廢的方法。
- 使用interrupt方法中斷執行緒。
class MyThread extends Thread {
volatile boolean stop = false;
public void run() {
while (!stop) {
System.out.println(getName() + " is running");
try {
sleep(1000);
} catch (InterruptedException e) {
System.out.println("week up from blcok...");
stop = true; // 在異常處理程式碼中修改共享變數的狀態
}
}
System.out.println(getName() + " is exiting...");
}
}
class InterruptThreadDemo3 {
public static void main(String[] args) throws InterruptedException {
MyThread m1 = new MyThread();
System.out.println("Starting thread...");
m1.start();
Thread.sleep(3000);
System.out.println("Interrupt thread...: " + m1.getName());
m1.stop = true; // 設定共享變數為true
m1.interrupt(); // 阻塞時退出阻塞狀態
Thread.sleep(3000); // 主執行緒休眠3秒以便觀察執行緒m1的中斷情況
System.out.println("Stopping application...");
}
}
notify()和notifyAll()有什麼區別?
notify可能會導致死鎖,而notifyAll則不會
任何時候只有一個執行緒可以獲得鎖,也就是說只有一個執行緒可以執行synchronized 中的程式碼
使用notifyall,可以喚醒 所有處於wait狀態的執行緒,使其重新進入鎖的爭奪佇列中,而notify只能喚醒一個。
wait() 應配合while迴圈使用,不應使用if,務必在wait()呼叫前後都檢查條件,如果不滿足,必須呼叫notify()喚醒另外的執行緒來處理,自己繼續wait()直至條件滿足再往下執行。
notify() 是對notifyAll()的一個最佳化,但它有很精確的應用場景,並且要求正確使用。不然可能導致死鎖。正確的場景應該是 WaitSet中等待的是相同的條件,喚醒任一個都能正確處理接下來的事項,如果喚醒的執行緒無法正確處理,務必確保繼續notify()下一個執行緒,並且自身需要重新回到WaitSet中.
sleep()和wait() 有什麼區別?
對於sleep()方法,我們首先要知道該方法是屬於Thread類中的。而wait()方法,則是屬於Object類中的。
sleep()方法導致了程式暫停執行指定的時間,讓出cpu該其他執行緒,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復執行狀態。在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。
當呼叫wait()方法的時候,執行緒會放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件呼叫notify()方法後本執行緒才進入物件鎖定池準備,獲取物件鎖進入執行狀態。
volatile 是什麼?可以保證有序性嗎?
一旦一個共享變數(類的成員變數、類的靜態成員變數)被volatile修飾之後,那麼就具備了兩層語義:
1)保證了不同執行緒對這個變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的,volatile關鍵字會強制將修改的值立即寫入主存。
2)禁止進行指令重排序。
volatile 不是原子性操作
什麼叫保證部分有序性?
當程式執行到volatile變數的讀操作或者寫操作時,在其前面的操作的更改肯定全部已經進行,且結果已經對後面的操作可見;在其後面的操作肯定還沒有進行;
x = 2; //語句1
y = 0; //語句2
flag = true; //語句3
x = 4; //語句4y = -1; //語句5
由於flag變數為volatile變數,那麼在進行指令重排序的過程的時候,不會將語句3放到語句1、語句2前面,也不會講語句3放到語句4、語句5後面。但是要注意語句1和語句2的順序、語句4和語句5的順序是不作任何保證的。
使用volatile 一般用於 狀態標記量 和 單例模式的雙檢鎖。