文章目錄
-
- 1. 對象鎖
-
- 1.1. 同步方法
- 1.2. 同步代碼塊(目前類對象鎖)
- 1.3. 同步代碼塊(傳入類對象鎖)
- 2. 類鎖
-
- 2.1. 同步靜态方法
- 2.2. 同步代碼塊(目前類class鎖)
多個程序或線程同時(或着說在同一段時間内)通路同一資源會産生并發(線程安全)問題。解決并發問題可以用鎖。單機情況下可以直接使用
synchronized
關鍵字實作的内置鎖。
每個
Java
對象都可以用做一個實作同步的鎖,這些鎖稱為内置鎖。線程進入同步代碼塊或方法的時候會自動獲得該鎖,在退出同步代碼塊或方法時會釋放該鎖。獲得内置鎖的唯一途徑就是進入這個鎖保護的同步代碼塊或方法。
Java
内置鎖是一個互斥鎖,這就意味着最多隻有一個線程能夠獲得該鎖,當線程
A
嘗試去獲得線程
B
持有的内置鎖時,線程
A
必須等待或者阻塞,直到線程
B
釋放這個鎖,如果線程
B
不釋放這個鎖,那麼線程
A
将永遠等待下去。
Java
的内置鎖基本上可以分為對象鎖和類鎖,對象鎖是用于對象執行個體方法或者對象執行個體上的,類鎖是用于類的靜态方法或者類的
class
對象上的。我們知道,一個類的執行個體對象可以有很多個,但是每個類隻有一個
class
對象,是以不同對象執行個體的對象鎖是互不幹擾的,但是每個類隻有一個類鎖。有一點必須注意的是,其實類鎖隻是一個概念上的東西,并不是真實存在的,它隻是用來幫助我們了解鎖定執行個體方法和靜态方法的差別的。
synchronized
隻是一個内置鎖的加鎖機制,當某個方法加上
synchronized
關鍵字後,就表明要獲得該内置鎖才能執行,并不能阻止其他線程通路不需要獲得該内置鎖的方法。
1. 對象鎖
1.1. 同步方法
同步方法,是對該對象加鎖,其他線程将無法通路需要擷取該對象鎖的方法和代碼塊。
public class Test{
public synchronized void print(){
System.out.println("hello world!");
}
}
上面代碼表示通路
print()
方法需要擷取
Test
執行個體對象的鎖。
1.2. 同步代碼塊(目前類對象鎖)
同步代碼塊,這種寫法也是鎖住該類的執行個體對象,和
1.1.
效果一樣,其他線程将無法通路需要擷取該對象鎖的方法和代碼塊。
public class Test{
public void print(){
synchronized(this){
System.out.println("hello world!");
}
}
}
上面代碼表示通路
print()
方法中的代碼塊需要擷取
Test
執行個體對象的鎖。
1.3. 同步代碼塊(傳入類對象鎖)
同步代碼塊,這種寫法鎖住傳入的對象,不影響需要擷取目前類對象鎖的方法和代碼塊的通路。
public class Test{
private byte[] lock = new byte[0];
public void print(){
synchronized(lock){
System.out.println("hello world!");
}
}
public synchronized void print1(){
System.out.println("123456");
}
}
執行
print()
方法裡面的同步代碼塊,會給
byte[]
對象
lock
加鎖,注意不是給
Test
的對象加鎖,也就是說
Test
對象的其它
synchronized
方法和代碼塊不會因為
print()
而被鎖。
print1()
方法可以正常通路。
2. 類鎖
類鎖修飾方法和代碼塊的效果和對象鎖是一樣的,因為類鎖隻是一個抽象出來的概念,類鎖和對象鎖是互不幹擾的。同樣,線程獲得對象鎖的同時,也可以獲得該類鎖,即同時獲得兩個鎖,這是允許的。
2.1. 同步靜态方法
因為靜态方法是所有對象執行個體共用的,對應着
synchronized
修飾的靜态方法的鎖也是唯一的,是以抽象出來個類鎖。其他線程将無法通路需要擷取該類鎖的方法和代碼塊。
public class Test{
public synchronized static void print(){
System.out.println("hello world!");
}
}
2.2. 同步代碼塊(目前類class鎖)
這種寫法,直接鎖定目前類的
class
對象,因為每個類隻有一個
class
對象,和
2.1.
效果一樣。其他線程将無法通路需要擷取該類鎖的方法和代碼塊。
public class Test{
public void print(){
synchronized(Test.class){
System.out.println("hello world!");
}
}
}