對實現了
Runnable
或者
Callable
接口類,能夠經過多線程執行同一實例的
run
或
call
方法,那麼對於同一實例中的局部變量(
非方法變量
)就會有多個線程進行更改或讀取,這就會致使數據不一致,
synchronized
(
關鍵字
)能夠解決多線程共享數據同步的問題
synchronized使用說明
做用範圍
synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有如下幾種:
-
修飾一個代碼塊
:被修飾的代碼塊稱爲同步語句塊,其做用的範圍是大括號{}括起來的代碼,做用的對象是調用這個代碼塊的對象
-
修飾一個非靜態方法
:被修飾的方法稱爲同步方法,其做用的範圍是整個方法,做用的對象是調用這個方法的對象
-
修改一個靜態的方法
:其做用的範圍是整個靜態方法,做用的對象是這個類的全部對象
-
修改一個類
:其做用的範圍是synchronized後面括號括起來的部分,做用主的對象是這個類的全部對象
高能提示:
No1 >
synchronized修飾的非靜態方法:
若是
一個對象
有
多個synchronized方法
,只要
一個線程
訪問了其中的
一個synchronized方法
,則這個線程
所屬對象
的
其它線程
不能
同時訪問
這個
對象
中
任何一個synchronized方法
No2 >
synchronized關鍵字是不能繼承的:
基類的方法
synchronized function(){}
在繼承類中並不自動是
synchronized function(){}
,而是變成了
function(){}
。繼承類須要你
顯式的指定
它的某個方法爲
synchronized方法
,能夠經過
子類調用父類的同步方法來實現同步
No3 > 針對synchronized修飾代碼塊和非靜態方法,本質上鎖的是代碼塊或非靜態方法對應的
對象
(
代碼塊是synchronized標註的變量,非靜態方法是所在類對應的實例
),若是是
不一樣的對象
是能夠同時訪問的
No4 > 實現同步是要很大的
系統開銷
做爲代價的,甚至可能形成
死鎖
,因此儘可能避免
無謂的同步控制
No5 > 每一個對象只有一個鎖(lock)與之相關聯
No6 > 在定義
接口方法
時不能使用
synchronized
關鍵字
No7 > 構造方法不能使用
synchronized關鍵字
,但可使用
synchronized代碼塊
來進行同步
1. 修飾一個代碼塊
public void syncCode(Object o) {
synchronized (o) {// 同步代碼塊}
}
上面的鎖就是
o
這個對象,固然多個線程同步須要保證
o
這個對象是
同一個
,這是有明確的對象做爲鎖的狀況,若是隻是想單純的讓某一段代碼同步,並無明確的對象做爲鎖,能夠建立一個特殊的
instance
變量來充當鎖
synchronized(o)
修飾的代碼塊,其中o
能夠取值一個對象
或者一個變量
或者this
亦或者Clz.class
public class Sync implements Runnable {
private byte[] lock = new byte[0];
public void syncCode() {
synchronized (lock) {// 同步代碼塊}
}
public void run ....
}
注
:
零長度的byte數組
對象建立起來將比任何對象都經濟,查看
編譯後的字節碼
,生成
零長度的byte[]
對象只需3條操做碼,而
Object lock = new Object()
則須要7行操做碼
2. 修飾一個非靜態方法
public synchronized void method() {// .....}
此時鎖的是調用這個同步方法的對象
3. 修飾一個靜態方法
public synchronized static void method() {// .....}
synchronized修飾的靜態方法鎖定的是這個類的全部對象
4. 修飾類
public class Sync implements Runnable {
public void syncCode() {
synchronized (Sync.class) {// 同步代碼塊}
}
public void run ....
}
和做用於靜態方法同樣,synchronized做用於一個類時,是給這個類加鎖,類的全部對象用的是同一把鎖
總結
- 線程同步的目的是爲了保護多個線程反問一個資源時對資源的破壞。
- 線程同步方法是經過鎖來實現,每一個對象都有切僅有一個鎖,這個鎖與一個特定的對象關聯,線程一旦獲取了對象鎖,其餘訪問該對象的線程就沒法再訪問該對象的其餘非同步方法
- 對於靜態同步方法,鎖是針對這個類的,鎖對象是該類的Class對象。靜態和非靜態方法的鎖互不干預。一個線程得到鎖,當在一個同步方法中訪問另外對象上的同步方法時,會獲取這兩個對象鎖。
- 對於同步,要時刻清醒在哪一個對象上同步,這是關鍵。
- 編寫線程安全的類,須要時刻注意對多個線程競爭訪問資源的邏輯和安全作出正確的判斷,對"原子"操做作出分析,並保證原子操做期間別的線程沒法訪問競爭資源。
- 當多個線程等待一個對象鎖時,沒有獲取到鎖的線程將發生阻塞。
- 死鎖是線程間相互等待鎖鎖形成的,在實際中發生的機率很是的小,一旦程序發生死鎖,程序將死掉