對實現了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對象。靜態和非靜態方法的鎖互不干預。一個線程獲得鎖,當在一個同步方法中訪問另外對象上的同步方法時,會獲取這兩個對象鎖。
- 對于同步,要時刻清醒在哪個對象上同步,這是關鍵。
- 編寫線程安全的類,需要時刻注意對多個線程競爭訪問資源的邏輯和安全做出正確的判斷,對"原子"操作做出分析,并保證原子操作期間別的線程無法訪問競爭資源。
- 當多個線程等待一個對象鎖時,沒有獲取到鎖的線程將發生阻塞。
- 死鎖是線程間相互等待鎖鎖造成的,在實際中發生的概率非常的小,一旦程序發生死鎖,程序將死掉