原子性問題的源頭是執行緒切換
Q:如果禁用 CPU 執行緒切換是不是就解決這個問題了?
A:單核 CPU 可行,但到了多核 CPU 的時候,有可能是不同的核在處理同一個變數,即便不切換執行緒,也有問題,
所以,解決原子性的關鍵是「同一時刻只有一個執行緒處理該變數,也被稱為互斥」,
如何做到呢?用「鎖」,
一、鎖模型
一)簡易鎖模型
一般看到的鎖模型長下面這樣,
但對于這個模型,會有幾個疑問:
- 鎖的是什么?
- 臨界區的這一堆代碼相關的都被鎖了?
- 保護的又是什么?

二)改進后的鎖模型
用下面這個模型來解釋就解答了上面幾個問題:
- 要保護的是臨界區中的資源 R
- 因此要為 R 創建一個對應的鎖 LR
- 需要處理資源 R 的時候先加鎖,處理完之后解鎖

要注意的是:
- 一個資源必須和鎖對應,不能用 A 鎖去鎖 B 資源
二、Java 提供的鎖技術
Java 提供了多種技術,這里僅談及 Synchronized,
Synchronized 關鍵字
Java 語言提供的 synchronized 關鍵字,就是鎖的一種實作,synchronized 關鍵字可以用來修飾方法,也可以用來修飾代碼塊,
class X {
// 修飾非靜態方法
synchronized void foo() {
// 臨界區
}
// 修飾靜態方法
synchronized static void bar() {
// 臨界區
}
// 修飾代碼塊
Object obj = new Object();
void baz() {
synchronized(obj) {
// 臨界區
}
}
}
Q:synchronized 沒看到 lock 和 unlock?
A:在編譯的時候會做轉換,synchronized起始的地方加鎖,結束的地方解鎖,
Q:那么 synchronized 鎖的是什么呢?
A:當修飾靜態方法時,鎖定的是當前類的 Class 物件,在上面的例子中就是 Class X;
當修飾非靜態方法時,鎖定的是當前實體物件 this,
當修飾代碼塊時,括號中寫的是啥就鎖啥,
(可能不準確)
Class 物件是用來保存類資訊的,可以理解為元資料?
實體物件則是每一個 new 出來的特殊的個體
Synchronized 實體
public class SynchronizedTT {
private int value = https://www.cnblogs.com/shuofxz/archive/2022/12/02/0;
//public void printValue() {
public synchronized void printValue() {
System.out.println(this.value);
}
public synchronized void addValue() throws InterruptedException {
Thread.sleep(1000);
this.value += 1;
}
}
// 開兩個執行緒,一個先呼叫 addValue(),另一個后呼叫 printValue()
??思考:如果 printValue() 不添加 synchronized 關鍵字,會造成什么樣的結果?
A:有可能會先執行了 addValue 在執行 print 但得到的卻是增加之前的數值,
三、鎖和受保護資源的關系
要點:
- 一把鎖可以保護多個資源
- 但是一個資源只能用一把鎖保護
- 受保護資源和鎖之間的關聯關系是 N:1 的關系
??思考:如果用多把鎖鎖同一個資源會出現什么情況?
下面例子:
synchronized 是不同的鎖,就和沒鎖一樣,
public class SynchronizedTT {
private static int value = https://www.cnblogs.com/shuofxz/archive/2022/12/02/0;
public synchronized void printValue() {
System.out.println(value);
}
public synchronized static void addValue() throws InterruptedException {
Thread.sleep(1000);
value += 1;
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/539029.html
標籤:其他
