2010年7月8日 星期四

Java 執行緒 - synchronized

第二部份的東西可能會比較難揣摩,我也是這樣學過來的,尤其是在執行緒共用互斥這方面等,需要花很多時間來理解。

首先先說明 JAVA 在執行緒中互斥的概念

大家最常看到的應該就是有一個銀行的範例了,
程式大致上是說有三個執行緒模擬了三個人(甲,乙,丙)會對同一個銀行帳戶近行提款或匯款的動作

用程式的角度看,是不是覺得三個人共用一個資源感覺有點危險?

譬如說,當甲來到提款機匯款前得知目前有5000元在帳戶中並開始執行匯款5000元
但匯款到一半,甲的 CPU time 結束了,這是換成乙來提款 2000 元
很順利的在 CPU time 之前完成並印出 "目前帳戶 餘額 3000 元"
這時再繼續換成甲來繼續執行匯款,很順利的完成後印出目前帳目金額
結果是 8000 元,可是甲一開始明明看到是 5000 元 那再匯入5000 不是一萬嗎?

上面的例子就是因為多執行緒共同存取同一資源而沒有同步的錯誤

說到同步的觀念就要介紹一個關鍵字 synchronized

相信有看過銀行帳戶的解決方法就是加上這個關鍵字就可以解決了
但是,為什麼?

這裡必須先介紹一些觀念首先上豎立子很明顯就是因為共用同一個資源加上又沒同步化所造成的錯誤,而上述的資源就是 "銀行帳戶",以下假設為:

public class Bank
{
private int money;
private String name;
public Bank(String name, int money){
this.money = money; this.name = name;
}

public synchronized void save(int m){ //加上關鍵字 synchronized
money += m;
}
public synchronized boolean withDraw(int m){ //加上關鍵字 synchronized
...... //略
}
public String getName(){
return name;
}
}


首先如果你在 主程式 main 方法裡建立了一個 Bank 物件

Bank bank = new Bank("MyBank", 10000);

其中 bank 就是 Bank 類別的一個實體。

在 Java 的定義中一個實體會有一個 "鎖定"

在執行緒的共用互斥架構下也可以稱為 monitor (監視)

這時後 如果有一個 執行緒在執行這個實體的 synchronized 方法時

其他執行緒就不能執行其他的 synchronized 方法

但可以執行非 synchronized 方法,譬如說:

甲在進行 save 的這個 synchronized 方法時

乙就不能執行 save 和 withDraw 這兩個 synchronized 方法

但乙可以執行 getName 這個 沒有 synchronized 修飾的方法

最後當執行 synchronized 方法的執行緒結束執行後

便會釋放該實體的鎖定

這時候如果外面還有很多執行緒在等待該鎖定時

就會開始爭搶該實體之鎖定

同樣的只會有一個執行緒取得並進入執行,其他的就在外面等。

下面以圖示或許會比較清楚,粉紅色箭頭代表了每個執行緒



說到這邊還有一個重點就是

一個實體就會相對有一個鎖定

所以如果今天建立了好幾個實體,如下:

Bank bank1 = new Bank("MyBank1", 10000);
Bank bank2 = new Bank("MyBank2", 10000);
Bank bank3 = new Bank("MyBank3", 10000);
Bank bank4 = new Bank("MyBank4", 10000);
Bank bank5 = new Bank("MyBank5", 10000);

這時候 每個實體可是有各自的鎖定的

但除了 static 的 synchronized 方法除外喔

下一篇 會說明

順便說明 wait 和 notify

沒有留言:

張貼留言