首頁技術文章正文

Java培訓之同步

更新時間:2017-06-30 來源:黑馬程序員Java培訓學院 瀏覽量:

好處:解決了線程安全問題。
弊端:相對降低性能,因為判斷鎖需要消耗資源,產(chǎn)生了死鎖。
 
定義同步是有前提的:
1,必須要有兩個或者兩個以上的線程,才需要同步。
2,多個線程必須保證使用的是同一個鎖。
 
java培訓項目實戰(zhàn)中,同步的第二種表現(xiàn)形式:
同步函數(shù):其實就是將同步關鍵字定義在函數(shù)上,讓函數(shù)具備了同步性。
 
同步函數(shù)是用的哪個鎖呢?
通過驗證,函數(shù)都有自己所屬的對象this,所以同步函數(shù)所使用的鎖就是this鎖。
 
當同步函數(shù)被static修飾時,這時的同步用的是哪個鎖呢?
靜態(tài)函數(shù)在加載時所屬于類,這時有可能還沒有該類產(chǎn)生的對象,但是該類的字節(jié)碼文件加載進內(nèi)存就已經(jīng)被封裝成了對象,這個對象就是該類的字節(jié)碼文件對象。
所以靜態(tài)加載時,只有一個對象存在,那么靜態(tài)同步函數(shù)就使用的這個對象。
這個對象就是 類名.class
在java培訓項目實戰(zhàn)中 
同步代碼塊和同步函數(shù)的區(qū)別?
同步代碼塊使用的鎖可以是任意對象。
同步函數(shù)使用的鎖是this,靜態(tài)同步函數(shù)的鎖是該類的字節(jié)碼文件對象。
 
在一個類中只有一個同步,可以使用同步函數(shù)。如果有多同步,必須使用同步代碼塊,來確定不同的鎖。所以同步代碼塊相對靈活一些。
-------------------------------------------------------
★考點問題:請寫一個延遲加載的單例模式?寫懶漢式;當出現(xiàn)多線程訪問時怎么解決?加同步,解決安全問題;效率高嗎?不高;怎樣解決?通過雙重判斷的形式解決。
//懶漢式:延遲加載方式。
當多線程訪問懶漢式時,因為懶漢式的方法內(nèi)對共性數(shù)據(jù)進行多條語句的操作。所以容易出現(xiàn)線程安全問題。為了解決,加入同步機制,解決安全問題。但是卻帶來了效率降低。
為了效率問題,通過雙重判斷的形式解決。
class Single{
private static Single s = null;
private Single(){}
public static Single getInstance(){ //鎖是誰?字節(jié)碼文件對象;
if(s == null){
synchronized(Single.class){
if(s == null)
s = new Single();
}
}
return s;
}
}
---------------------------------------------------------
同步死鎖:通常只要將同步進行嵌套,就可以看到現(xiàn)象。同步函數(shù)中有同步代碼塊,同步代碼塊中還有同步函數(shù)。
 java培訓實戰(zhàn)項目中
線程間通信:思路:多個線程在操作同一個資源,但是操作的動作卻不一樣。
1:將資源封裝成對象。
2:將線程執(zhí)行的任務(任務其實就是run方法。)也封裝成對象。
 
等待喚醒機制:涉及的方法:
wait:將同步中的線程處于凍結狀態(tài)。釋放了執(zhí)行權,釋放了資格。同時將線程對象存儲到線程池中。
notify:喚醒線程池中某一個等待線程。
notifyAll:喚醒的是線程池中的所有線程。
 
注意:
1:這些方法都需要定義在同步中。 
2:因為這些方法必須要標示所屬的鎖。
你要知道 A鎖上的線程被wait了,那這個線程就相當于處于A鎖的線程池中,只能A鎖的notify喚醒。
3:這三個方法都定義在Object類中。為什么操作線程的方法定義在Object類中?
因為這三個方法都需要定義同步內(nèi),并標示所屬的同步鎖,既然被鎖調(diào)用,而鎖又可以是任意對象,那么能被任意對象調(diào)用的方法一定定義在Object類中。
 
wait和sleep區(qū)別: 分析這兩個方法:從執(zhí)行權和鎖上來分析:
wait:可以指定時間也可以不指定時間。不指定時間,只能由對應的notify或者notifyAll來喚醒。
sleep:必須指定時間,時間到自動從凍結狀態(tài)轉成運行狀態(tài)(臨時阻塞狀態(tài))。
wait:線程會釋放執(zhí)行權,而且線程會釋放鎖。
Sleep:線程會釋放執(zhí)行權,但不是不釋放鎖。
 
線程的停止:通過stop方法就可以停止線程。但是這個方式過時了。
停止線程:原理就是:讓線程運行的代碼結束,也就是結束run方法。
怎么結束run方法?一般run方法里肯定定義循環(huán)。所以只要結束循環(huán)即可。
第一種方式:定義循環(huán)的結束標記。
第二種方式:如果線程處于了凍結狀態(tài),是不可能讀到標記的,這時就需要通過Thread類中的interrupt方法,將其凍結狀態(tài)強制清除。讓線程恢復具備執(zhí)行資格的狀態(tài),讓線程可以讀到標記,并結束。
 
---------< java.lang.Thread >----------
interrupt():中斷線程。
setPriority(int newPriority):更改線程的優(yōu)先級。
getPriority():返回線程的優(yōu)先級。
toString():返回該線程的字符串表示形式,包括線程名稱、優(yōu)先級和線程組。
Thread.yield():暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程。
setDaemon(true):將該線程標記為守護線程或用戶線程。將該線程標記為守護線程或用戶線程。當正在運行的線程都是守護線程時,Java 虛擬機退出。該方法必須在啟動線程前調(diào)用。
join:臨時加入一個線程的時候可以使用join方法。
當A線程執(zhí)行到了B線程的join方式。A線程處于凍結狀態(tài),釋放了執(zhí)行權,B開始執(zhí)行。A什么時候執(zhí)行呢?只有當B線程運行結束后,A才從凍結狀態(tài)恢復運行狀態(tài)執(zhí)行。


本文版權歸黑馬程序員Java培訓學院所有,歡迎轉載,轉載請注明作者出處。謝謝!

作者:黑馬程序員Java培訓學院

首發(fā):http://java.itheima.com/



分享到:
在線咨詢 我要報名
和我們在線交談!