簡(jiǎn)書(shū) 賈小強(qiáng)
轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝!
同步針對(duì)的是多線程。同步的方法或代碼塊同時(shí)只能由一個(gè)線程執(zhí)行。
Java支持多線程來(lái)執(zhí)行。這可能會(huì)導(dǎo)致兩個(gè)或多個(gè)線程訪問(wèn)同一個(gè)字段或?qū)ο?。同步是一個(gè)使所有并發(fā)執(zhí)行的線程同步的過(guò)程。同步避免了由于共享內(nèi)存視圖不一致而導(dǎo)致的內(nèi)存一致性錯(cuò)誤。當(dāng)一個(gè)方法被聲明為同步時(shí),如果一個(gè)線程正在執(zhí)行同步方法,線程保存該方法對(duì)象的監(jiān)視器(monitor),同時(shí)該線程被阻塞,直到該線程釋放監(jiān)視器(monitor)為止。
同步在Java中使用synchronized關(guān)鍵字實(shí)現(xiàn)。可以在類(lèi)中定義的方法或塊使用同步關(guān)鍵字。關(guān)鍵字不能與類(lèi)定義中的局部變量一起使用。
對(duì)象級(jí)別鎖
對(duì)象級(jí)別鎖是一種當(dāng)您想同步非靜態(tài)方法或非靜態(tài)代碼塊時(shí),只有一個(gè)線程能夠在類(lèi)的給定實(shí)例上執(zhí)行代碼塊的機(jī)制。應(yīng)該始終這樣做,使實(shí)例級(jí)數(shù)據(jù)線程安全。這可以做如下:
public class DemoClass
{
public synchronized void demoMethod(){}
}
或
public class DemoClass
{
public void demoMethod(){
synchronized (this)
{
//other thread safe code
}
}
}
或
public class DemoClass
{
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
}
類(lèi)級(jí)別鎖
類(lèi)級(jí)鎖定防止在運(yùn)行時(shí)多個(gè)線程進(jìn)入所有可用實(shí)例中的同步塊中。這意味著,如果在運(yùn)行時(shí)有100 DemoClass實(shí)例,那么只有一個(gè)線程可以在同一時(shí)間在任何一個(gè)實(shí)例上執(zhí)行demomethod(),對(duì)其他線程而言所有其他的實(shí)例將被鎖。這樣做總是為了使靜態(tài)數(shù)據(jù)線程安全。
public class DemoClass
{
public synchronized static void demoMethod(){}
}
或
public class DemoClass
{
public void demoMethod(){
synchronized (DemoClass.class)
{
//other thread safe code
}
}
}
或
public class DemoClass
{
private final static Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
}
一些重要的事項(xiàng)
- 在Java中為了保證沒(méi)有兩個(gè)線程可以同時(shí)執(zhí)行一個(gè)同步的方法,這就需要相同的鎖。
- 同步關(guān)鍵字只能用于方法,代碼塊和final字段。這些方法或塊既可以是靜態(tài)的也可以是非靜態(tài)的。
- 當(dāng)有一個(gè)線程進(jìn)入Java同步方法或塊的時(shí)候獲取鎖,離開(kāi)Java同步方法或塊的時(shí)候釋放鎖。線程完成同步方法,或由于任何錯(cuò)誤或異常,鎖都會(huì)被釋放。
- Java同步關(guān)鍵詞是可重入的,這意味著如果一個(gè)Java同步方法調(diào)用另一個(gè)需要相同的鎖的同步方法,當(dāng)前線程持有鎖,能直接進(jìn)入,不需要有獲取鎖。
- 如果使用Java同步塊的對(duì)象為空J(rèn)ava同步將拋出NullPointerException。例如,在上面的代碼示例,如果鎖被初始化為null,同步(鎖)將拋出NullPointerException。
- Java同步會(huì)消耗您的應(yīng)用程序性能。所以絕對(duì)必要時(shí)才使用同步。另外,考慮使用同步代碼塊來(lái)同步代碼中的關(guān)鍵部分。
- 靜態(tài)同步和非靜態(tài)同步方法可能同時(shí)或并發(fā)地運(yùn)行,因?yàn)樗鼈冩i定在不同的對(duì)象上。
- 根據(jù)Java語(yǔ)言規(guī)范不能使用同步關(guān)鍵詞在構(gòu)造函數(shù)上,這是違法的,會(huì)導(dǎo)致編譯錯(cuò)誤。
- 不要同步非final字段。因?yàn)榉莊inal字段的引用可能隨時(shí)改變,不同的線程可能在不同的對(duì)象上同步,即根本不同步。最好是使用字符串類(lèi),它已經(jīng)是不可變的,并且聲明為final的。
Happy Learning !!