1. 程式人生 > >java 多執行緒 鎖 synchronized 面試題

java 多執行緒 鎖 synchronized 面試題

早上上網看部落格的時候看見一道面試題。。便因此糾結了一天:

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(這裡是物件鎖){},只要物件鎖一樣,那一個執行緒在執行時,別的執行緒是無法執行的
  • 修飾靜態方法,這時候只要是同一個類產生的例項,就被鎖起來,不要求物件必須一致