1. 程式人生 > >javaSE (三十五)多執行緒 ( 多執行緒實現方法和區別、同步程式碼塊和方法(執行緒安全))

javaSE (三十五)多執行緒 ( 多執行緒實現方法和區別、同步程式碼塊和方法(執行緒安全))

主要還是熟悉api,熟悉方法,簡單,需要多實踐


1、 多執行緒實現方法和區別:

  1. 多執行緒實現的兩種方法:
    1)類繼承Thread類或實現Runnable介面,重寫run()方法
    2)建立Thread的子類物件(需要開幾個執行緒就建立幾個物件,可建立匿名內部類)
    3)子類物件.start()或者將實現了Runnable介面的物件當作引數放到Thread構造方法裡再子類物件.start()
    也可以採用匿名類的方法重寫Thread裡面的run()方法,將我們要執行的語句寫到run()方法裡面,然後直接.start()

多執行緒的要執行的程式碼主要就是寫在重寫的run方法裡,子類如果重寫了run,那就呼叫子類的run,如下,如果採用匿名類,因為編譯看父類,執行看子類,如果子類沒有重寫run,那就直接用父類重寫過的run

Thread的run原始碼,如果子類不為空,就呼叫子類的run:

 public void run() {
        if (target != null) {
            target.run();
        }
    }

繼承Thread類如果需要在幾個執行緒裡面共享的資料,比如,1000張票,四個視窗賣,這個票需要變成靜態的,就是在類載入的同時載入進方法區的靜態區,由執行緒所共享,但是實現Runnable介面就不需要了,因為只建立了一個類,然後用thread的構造方法建立四個執行緒一起執行這個類
2. 兩種方法原始碼的區別:
1)繼承Thread:由於子類重寫了Thread的run(),當呼叫start()的時候,直接找子類的run()方法
2)實現Runnable

:建構函式中傳入了Runnable的引用,成員變數記住了它,start()呼叫run()方法時內部判斷成員變數Runnable的引用是否為空,不為空的時候編譯看的是Runnable的run(),執行時執行的是子類的run()方法
3. 寫程式碼時的區別
1) 繼承Thread:好處是可以直接使用Thread類中的方法,程式碼簡單,弊端是如果已經有了父類,就不能用這種方法(Java中每個類都只能繼承一個類,但可以實現多個介面
2)實現Runnable:好處是即使自己定義的執行緒類有了父類也沒關係,可以實現多個介面;弊端是不能直接使用Thread中的方法需要

2、同步程式碼塊和方法:
將程式碼塊或者方法用鎖物件鎖起來,這樣在完整低執行了一次程式碼塊或者方法後CPU才會切換執行緒(也就是說,執行緒之間不干擾,是執行緒安全

的)
synchronized(鎖物件){方法}: 同步程式碼塊,鎖機制,鎖物件可以是任意的,但是鎖只能是相同的類(匿名類就不行),如果用引用資料型別變數(比如自己建立的物件)當作鎖物件,必須是靜態的,static
synchronized 方法(){}: 非靜態同步方法,直接用關鍵字修飾方法,其鎖物件是this
static synchronized 方法(){}: 靜態同步方法,直接用關鍵字修飾方法,其鎖物件是位元組碼物件(就像是建立了同步程式碼塊然後把鎖物件當作引數放到小括號裡)

注意:巢狀同步程式碼塊會造成死鎖,最好不要巢狀