黑馬程式設計師----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的執行權