java 多執行緒 鎖 synchronized 面試題
阿新 • • 發佈:2019-02-15
早上上網看部落格的時候看見一道面試題。。便因此糾結了一天:
public class TestSync2 implements Runnable {
int b = 100;
synchronized void m1() throws InterruptedException {
b = 1000;
Thread.sleep(500); //6
System.out.println("b=" + b);
}
synchronized void m2() throws InterruptedException {
Thread.sleep(250 ); //5
b = 2000;
}
public static void main(String[] args) throws InterruptedException {
TestSync2 tt = new TestSync2();
Thread t = new Thread(tt); //1
t.start(); //2
tt.m2(); //3
System.out.println("main thread b=" + tt.b); //4
}
@Override
public void run() {
try {
m1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
程式執行結果?
答案是:
/**
* main thread b = 2000
* b=1000
* 或者
* main thread b = 1000
* b=1000
*/
跟我自己做出來的答案肯定是有出入的,接下來是我自己的分析,大家有什麼見解都可以留言,因為我對分析中的一個地方不太確定:
- 首先從main開始執行,當t.start()後會開啟一個執行緒,開啟執行緒會耗費時間,而因為主執行緒正在執行,所以繼續往下走
- tt.m2(),主執行緒直接去呼叫了m2()方法,因為m2方法是同步的,所以此時是不會被t執行緒搶到的,Thread.sleep(250)會使主執行緒休眠,但是並不會釋放鎖,m2執行完成後,b=2000
這時候t執行緒也啟動好了,有執行緒的繼承性得知在一個執行緒中開啟另一個執行緒,這兩個執行緒的優先順序是相等的,所以t執行緒和主執行緒互搶執行權,這時就分兩種執行情況了:
- 主執行緒搶到執行權,則列印 main thread b=2000,接著t執行緒執行,run方法中呼叫了m1,b=1000,Thread.sleep(500),但是因為主執行緒已經沒有程式碼可執行了,所以t執行緒醒後繼續執行,列印b=1000
- t執行緒搶到執行權,b=1000,Thread.sleep(500),睡眠後,主執行緒又搶到執行權,所以列印 main thread b=1000,然後t執行緒睡醒,列印b=1000
在這個題中,因為加了鎖,所以是不存在可見性問題的,我唯一不太確定的地方就是main方法中,t.start()後,是否是因為t.start()啟動執行緒會花時間,所以繼續讓主執行緒執行到了tt.m2()方法,大家有什麼見解的,可以留言一起討論.
關於synchronized關鍵字我們這裡簡單提一下:
同步作用在以下3個地方:- 修飾方法(這時的鎖就是此物件的例項this),一個執行緒在執行這個物件的同步方法時,其他執行緒不得執行同一個物件的同步方法,不過可以執行同一個物件的非同步方法和不同物件的同步方法
- 同步程式碼塊,一樣的,synchronized(這裡是物件鎖){},只要物件鎖一樣,那一個執行緒在執行時,別的執行緒是無法執行的
- 修飾靜態方法,這時候只要是同一個類產生的例項,就被鎖起來,不要求物件必須一致