1. 程式人生 > >黑馬程式設計師----Java基礎之多執行緒

黑馬程式設計師----Java基礎之多執行緒

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a>、期待與您交流! ---------

多執行緒

程序:是一個正在執行中的程式.每一個程序都有一個執行順序.該順序是一個執行路徑,或者叫一個

執行緒:就是程序的一個獨立的控制單元,執行緒在控制這程序的執行

一個程序至少有一個執行緒

Java VM啟動的時候會有一個程序java.exe.該程序中至少有一個執行緒負責java程式的執行,而且這個執行緒執行的程式碼存在於main方法中.該執行緒稱之為主執行緒

擴充套件:其實更細節說明jvm,jvm啟動不止一個執行緒,還有負責垃圾回收機制的執行緒任何在自定義的程式碼中,自定義一個執行緒呢?

通過對API的查詢,Java已經提供了對執行緒這類事物的描述,就是Thread

建立執行緒的第一種方式:繼承Thread類

步驟:

1.  定義類,繼承Thread    2.  複寫Thread類中的run方法.      3.  呼叫執行緒的start方法,該方法有兩個作用,啟動執行緒,呼叫run方法

發現執行結果每一次都不同,因為多個執行緒都獲取cpu的執行權,cpu執行到誰,誰就執行

明確一點,在某個時刻,只能有一個程式在執行(多核除外),cpu在作著快速的切換,以達到看上去同時執行的效果,我們可以形象的把多執行緒的執行行為在互相搶奪cpu的執行權

這就是多執行緒的一個特性:隨機性,誰搶到誰執行,至於執行多長,cpu說了算.

為什麼要覆蓋潤方法呢?

Thread類用於描述執行緒.

該類就定義了一個功能,用於儲存執行緒要執行的程式碼,該儲存功能就是run方法.也就是說Thread類中的run方法,用於儲存執行緒要執行的程式碼.

執行緒的執行示意圖:




執行緒都有自己的編號:和預設名稱,格式為:  Thread-編號  該編號從0開始.


獲取名稱的程式碼為:Thread.currentThread().getName()

繼承Thread方法的執行緒示例:


建立執行緒的第二種方式:實現Runnable介面

步驟:

定義實現Runnbale介面

覆蓋Runnbale介面中的run方法.將執行緒要執行的程式碼放到該run方法中

通過Thread建立執行緒物件

將Runnable介面的子類物件作為實際引數傳遞給Thread類的建構函式

為什麼要將Runnable介面定義的子類物件傳遞給Thread類的建構函式呢?

因為,自定義的run方法所屬的物件是Runnable介面的子類物件,所以要讓執行緒去指定指定物件的run方法,就必須明確該run方法所屬物件

呼叫Thread類的start方法開啟執行緒並呼叫Runnable介面子類的run方法

實現方式和繼承方式有什麼區別

實現方式的好處:避免了單繼承的侷限性,在定義執行緒時,建議使用實現方式:

兩種的區別:

繼承Thread:執行緒程式碼存放Thread子類的run方法中

實現Runnable:存在介面的子類run方法中

多執行緒的執行出現了安全問題.

問題的原因:

當多條語句在操作同一個執行緒共享資料時,一個執行緒對多條語句只執行了一部分,還沒有執行完,另一個執行緒參與進來執行.導致共享資料的錯誤

解決辦法:

對多條操作共享資料的語句,只能讓一個執行緒都執行完.在執行過程中,其它執行緒不可以參與執行

Java對於多執行緒的安全問題提供了專業的解決方式:就是同步程式碼塊:

synchronized(物件)

{

需要被同步的程式碼;

}

賣票的小例子:


物件如同鎖.持有鎖的執行緒可以在同步中執行.

沒有持有鎖的執行緒即使獲取cpu的執行權,也進不去,因為沒有獲取鎖

同步的前提:

1.  必須保證要有兩個或者兩個以上的執行緒

2.  必須是多個執行緒使用同一個鎖

必須保證同步中只有一個執行緒在執行

同步的好處:解決了多執行緒的安全問題

同步的弊端:多個執行緒需要判斷鎖,較為消耗資源;

同步函式:

函式需要被物件呼叫.那麼函式都有一個所屬的物件引用.就是this.所以同步函式使用的鎖是this

如果同步函式被靜態修飾後,使用的鎖是什麼呢?

通過驗證,發現不是this.因為靜態方法中也不可以定義this

靜態進記憶體時,記憶體中沒有本類物件,但是一定有該類對應的位元組碼檔案物件.

類名.class  該物件的型別是Class

靜態同步方法,使用的鎖是該方法所在類的位元組碼檔案物件      類名.class

死鎖:

同步中巢狀同步:


執行緒間通訊:

思考:wait().notify(),nitifyAll(),用來操作執行緒為什麼定義在了Object類中?

1.這些方法存在同步中

2.使用這些方法是必須要標識所屬的同步的鎖

3.鎖可以是任意物件,所以任意物件呼叫的方法一定要定義Object類中

思考2:wait().sleep()有什麼區別?

wait():釋放資源,釋放鎖

sleep():釋放資源,不釋放鎖

執行緒間通訊:其實就是多個執行緒在操作同一個資源;但是操作的動作不同:

等待喚醒機制:生產消費商品例子



1.5版本新特性:

將同步中synchronized替換成現實lock操作

將object中的wait(0,notify(),notifyAll(),替換成condition物件,該物件可以lock鎖進行獲取.如下示例中實現了本方只喚醒對方


停止執行緒:

1.  定義迴圈結束標記

因為執行緒執行程式碼一般都是迴圈,只要控制了迴圈即可

2.  使用interrupt(中斷)方法

該方法是結束執行緒的凍結狀態,使執行緒回到執行狀態中來

注:stop方法已經過時,不在使用

守護執行緒:setDaemon();

將該執行緒標記為守護執行緒或使用者執行緒.當正在執行的執行緒都是守護執行緒時,Java虛擬機器退出

join方法:當程式執行到該方法是,那個執行緒呼叫該方法是,該執行緒會強制獲取cpu的執行權,當該執行緒執行完後其它執行緒才開始爭奪cpu的執行權