看來你想要做的是:
- 寫從1到50的所有數字
System.out
- 有這個執行完成通過兩個併發線程
首先,讓我們來看看代碼中發生了什麼:每個數字都會打印兩次。這樣做的原因是,i
是me
一個實例變量,你Thread
。因此,每個Thread
都有其自己的i
,即它們不共享該值。
爲了使兩個線程共享相同的值,我們需要構建me
時傳遞相同的值。現在,隨着原始int
這樣做不會幫助我們很多,因爲傳遞一個int
如果我們沒有一個參考,因此這兩個線程將仍然獨立的內存位置運行。
讓我們定義一個新的類,Value
保存用於我們的整數:(編輯:同樣也可以通過傳遞數組int[]
,其也保持參考其內容的存儲位置來實現)
現在
class Value{
int i = 1;
}
,main
可以實例Value
類型的一個對象和參考將它傳遞給兩個線程。這樣,他們可以訪問相同的內存位置。
class Me extends Thread {
final Value v;
public Me(Value v){
this.v = v;
}
public void run(){
for(; v.i < 50; v.i++){
// ...
}
public static void main(){
Value valueInstance = new Value();
Me a = new Me(valueInstance);
Me b = new Me(valueInstance);
}
}
i
現在不兩次每次打印。但是,您會注意到行爲仍然不符合要求。這是因爲操作交錯:a
可以讀取i
,讓我們說,這個值是5.接下來,b
遞增的i
值,將新值。 i
現在是6然而,a
並仍讀舊值,5,並重新打印5,即使b
剛剛打印5。
爲了解決這一點,必須鎖定實例v
,即Value
類型的對象。 Java提供了關鍵字,它將在執行塊內的所有代碼期間保持鎖定狀態。但是,如果你只是同步你的方法,你仍然不會得到你想要的。假設你寫:
public void run(){ synchronized(v) {
for(; v.i < 50; v.i++) {
// ...
}}
你的第一個線程將獲得鎖,但直到整個循環已經執行從不釋放它(這是當i
的值爲50)。因此,您必須在安全的情況下以某種方式釋放鎖。嗯......你run
方法的唯一代碼,不依賴於i
(因此並不需要被鎖定)爲sleep
,這也很幸運在這裏線程中花費時間最多的。
既然一切是在循環體中,一個簡單的塊將不會執行。我們可以使用Semaphore
來獲得一個鎖。因此,我們在main
方法中創建了一個Semaphore
實例,並且與v
類似,將它傳遞給兩個線程。然後,我們可以獲得並釋放對Semaphore
的鎖定,讓兩個線程都有機會獲取資源,同時保證安全。
下面是將這樣的伎倆代碼:
public class Me extends Thread {
public int name;
final Value v;
final Semaphore lock;
public Me(Value v, Semaphore lock) {
this.v = v;
this.lock = lock;
}
public void run() {
try {
lock.acquire();
while (v.i <= 50) {
System.out.println("Thread" + name + " : " + v.i);
v.i++;
lock.release();
sleep(100);
lock.acquire();
}
lock.release();
} catch (Exception e) {
System.out.println("some problem");
}
}
public static void main(String[] args) {
Value v = new Value();
Semaphore lock = new Semaphore(1);
Me a = new Me(v, lock);
Me b = new Me(v, lock);
a.name = 1;
b.name = 2;
a.start();
b.start();
}
static class Value {
int i = 1;
}
}
注:由於我們是在循環的末尾獲取鎖,我們也必須在循環後釋放,或資源永遠不會釋放。另外,我將for
-loop更改爲while
循環,因爲我們需要在第一次釋放鎖之前更新i
,或者其他線程可以再次讀取相同的值。
你爲什麼想做這個數字? – 2014-10-05 00:40:32
是的,你爲什麼要這樣做?這是一個家庭作業問題還是一些你想嘗試的隨機事物? – 2014-10-05 00:49:55
那麼,你的變量'i'是一個局部變量,它只在循環內部和執行循環的線程內部可用。但是,你確定你希望你的兩個線程以書面形式交替嗎?你可以通過讓一個線程觸發另一個線程來實現這一點,反之亦然,但基本上可以讓你的程序順序運行。或者,你可以讓你的兩個線程以任意順序寫入,例如,Thread1寫入1,Thread1寫入2,Thread2寫入3,... **編輯**:對不起,實際上你的'i'不是局部變量,但你需要自動更新它。 – 2014-10-05 00:58:05