|Practical Java| Chapter 5 Multithreading
for ease and speed in doing a thing do not give the work lasting solidity or
exactress of beauty!. ----Plutarch, life of Pericles
要進行多線程編程, 首先該好好理解併發編程原理(concurrent programming).
("Instance 函數或者變量 " --- 指的是類的成員)
46> 面對 Instance 函數, synchronized鎖定的是對象而非函數或代碼.
關鍵字 synchronized 可用作函數的修飾符(Modifier), 亦可以用作函數的
語句. 應該注意到這裏的xynchronized 並不是平常認爲的互拆器(mutex)
或者關鍵區 (critical section).
對於 Instance 方法, 關鍵詞 synchronized 其實並不鎖定函數或代碼, 她鎖
定的是對象, Remember: 每個對象只有一個lock (機鎖)與之相關聯.
當 synchronized 被當作函數修飾符的時候, 她所取得的lock 將被交給函數
調用者(某對象), 如果synchronized 用於 Object reference, 則取得的 lock 將被
交給該reference 所指的對象.
對於同一個對象進行同步控制意味着: [調用函數] 的線程將會取得對象的
lock. 持有 [對象A 的lock] 意味着另一個通過 synchronized 函數或synchronized
語句來申請 [對象A的lock]的線程, 在該 lock 被釋放之前將無法獲得滿足.
synchronized 方法或 synchronized 區段內的代碼在同一時刻下可由多個線程
執行 ----- 只要是對不同的對象調用該函數.
Ex:
class Foo extends Thread{
private int val;
public Foo(int v){val = v;}
public synchronized void printVal(int v){
while(true){System.out.println(v); }
}
public void run(){printVal(val); }
}
class Bar extends Thread{
private Foo sameFoo;
public Bar(Foo f){ sameFoo = f; }
public void run(){sameFoo.printVal(2); }
}
class PP{
public static void main(String []args){
Foo f1 = new Foo(1);
f1.start();
Bar b = new Bar(f1);
b.start();
Foo f2 = new Foo(3);
f2.start();
}
}
在實例中, 首先create Foo 對象, 此線程進入一個無限循環因此Foo 對象的lock
永遠得不到釋放; 然後create Bar對象, 此線程對同一個 Foo對象調用同一個
synchronized printVal()方法, 此時這個調用發生阻塞(block), 直到前一次執行結
束. ----- 所以在輸出結果中是不可能出現 "2 " 的.
PS: 同步機制(synchronized) 鎖定的是對象, 而不是函數或代碼. 函數或代碼區段
被聲明爲synchronized 並非意味着她在同一時刻只能由一個線程執行.
Java 不允許將construct Method 聲明爲synchronized, 原因是兩個線程併發調
用同一個construct Method時,她們各自操控的是同一個class 的兩個不同
實體的內存. 然而如果在construct 內含了彼此競爭共享資源的代碼, 則
必須同步控制那些資源以迴避衝突.
47> 弄清楚 synchronized statics 函數與 synchronized instance函數間的差異
同步控制中的 instance函數 / static 函數 / objects / class literals
情況下得到的 locks不同, 因此在決定互斥 (mutual exclusion)行爲時一定
要小心謹慎.
48> 以 [private 數據 + 相應的訪問函數(accessor) 替換 [public/protected數據]
使用synchronized 函數編碼, 目的在於使數據免遭混亂之災. 爲了適當保護數據,
你必須確保正確的聲明和訪問她們. 這一點很重要.
要想完全保護 synchronized 函數中的數據, 必須令這些數據成爲class 的private
成員. 這是唯一可行的辦法.
50> 訪問共享變量時請使用 synchronized 或 volatile
51> 在單一操作(single Operation) 中鎖定所有用到的對象