內建鎖(隱式鎖)和顯示鎖
阿新 • • 發佈:2019-01-01
1.內建鎖:
(1)原理:通過內部的一個叫做監視器鎖的原理來實現的,但是監視器鎖本質又是依賴於底層的作業系統的Mutes Lock來實現的,作業系統之間實現執行緒的切換需要從使用者態轉換到核心態,這個成本非常高,狀態之間轉換需要很長的時間,所以內建鎖效率較低。
(2)如何加鎖和釋放鎖:
鎖物件越小越好
內建鎖獲得鎖和釋放鎖是隱式的,進入synchronized修飾的程式碼塊就獲得鎖,走出就釋放鎖
(3)通訊
wait(),notify()
wait()會立刻釋放當前的鎖,並進入等待狀態,等待到相應的notify並重新獲得鎖過後才能繼續執行;notify()不會立刻釋放鎖,必須要等待notify所線上程執行完synchronized塊中的所有程式碼才會釋放
(4)編碼
模式較為簡單,不必顯式的加鎖釋放鎖
(5)靈活性
一旦進入等待狀態沒既不能中斷也不能取消,容易產生飢餓和死鎖的問題
線上程呼叫notify方法時,會隨機選擇相應的物件的等待佇列的一個執行緒將其喚醒,而不是按照FIFO(先入先出佇列)。
(6)效能
與顯示鎖相效率較低,但是java6以後效能差別不大
2.顯式鎖
參考原文:http://blog.csdn.net/ghsau/article/details/7461369/
在一些內建鎖無法滿足需求的情況下,顯式鎖可以作為一種高階工具。當需要一些高階功能時才應該使用ReentrantLock,這些功能包括:可定時,可輪詢,可中斷,公平佇列,及非塊結構的鎖。否則還是應該優先使用synchronized。
讀寫鎖: ReadWriteLock
class Data {
private int data;// 共享資料
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public void set(int data) {
rwl.writeLock().lock();// 取到寫鎖
try {
System.out.println(Thread.currentThread().getName() + "準備寫入資料");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
System.out.println(Thread.currentThread().getName() + "寫入" + this.data);
} finally {
rwl.writeLock().unlock();// 釋放寫鎖
}
}
public void get() {
rwl.readLock().lock();// 取到讀鎖
try {
System.out.println(Thread.currentThread().getName() + "準備讀取資料");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "讀取" + this.data);
} finally {
rwl.readLock().unlock();// 釋放讀鎖
}
}
}
public static void main(String[] args) {
final Data data = new Data();
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < 5; j++) {
data.set(new Random().nextInt(30));
}
}
}).start();
}
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < 5; j++) {
data.get();
}
}
}).start();
}
}