2012-10-26 18 views
0

我正在進行多線程編程並遇到有線問題:對象更新只對另一個線程部分可見。下面是僞代碼:由不同線程更新的對象僅對另一個線程部分可見

初始狀態:線程A正在運行,並且線程B被阻塞

Class C { 
    public int i; 
    public String s; 
} 

線程A:

... 
// c is an object of class C and is accessible by both thread A and B 
c.i = 10; 
c.s = "success"; 
wakeup thread B: 

線程B:

// after wakeup 
assert(c.i == 10); 
assert(c.s.equals("success")); 

的問題是:在線程B中,有時字符串cs的值實際上是null。但我期望它具有「成功」的價值。另一方面,如果我在斷言語句之前放置了Thread.sleep(有時),那麼我可以看到c.s的期望值。我不知道爲什麼會發生。

我試圖將提交的變量s聲明爲volatile,但它沒有幫助。

謝謝!

更新 感謝所有答覆/答案。經過更多的實驗和調查後,我認爲這是我正在使用的框架的一個錯誤。該框架管理線程的掛起/恢復,並且當有許多併發請求/連接(如10k線程)時,它會變得雜亂無章。

+0

你能顯示實際的代碼嗎?因爲多線程不能以你應該的方式工作。即使在線程A完成工作之前,線程B也可以開始工作。 –

+1

揮發性物質應該起作用。您是否將String標記爲volatile或整個c對象爲volatile? –

+0

你用什麼機制來喚醒線程B部分? – Tudor

回答

2

當你在使用多線程技術時,那麼你的所有線程,在他們當中分享你的CPU。不確定哪個線程將在之前完成,哪個線程將最後完成。最後開始的Thread可能可能最先結束。這一切都取決於使用的CPU調度算法。

所以,如果你沒有對其中任何調用sleepwait運行兩個線程(taht是沒有任何interrupting他們的),那麼CPU分配將兩個Threads之間切換。所以,即使在Thread A完成之前,Thread B肯定有可能獲得CPU。

但是,當您的Thread B處於睡眠狀態的時間足以讓A完成作業時,那麼CPU將分配給線程A直到此時。因此,它有足夠的時間來完成它的工作(只要你有隻有兩個線程AB是在runnable狀態當時)

這就是爲什麼你multithreading代碼的結果,是絕不相同。它不斷改變多次運行。所以,當你運行一些10 - 15次代碼時。你可以看到這種差異。

,以確保在Thread B之前你Thread A完成後,您可以在您的Thread BThread A使用了特定的實例調用wait。然後Thread A完成時,它會調用notify通知Thread B,它已經完成了作業,然後Thread B可以繼續,

+1

我同意rohit,它的總數取決於線程時間表。沒有確定哪些將首先執行,哪些將在後面執行。每次你會得到不同的結果。 –

2

你需要線程A和B之間的一些同步

線程A:

c.i = 10; 
c.s = "success"; 
c.notify() 

線程B:

c.wait() 
assert(c.i == 10); 
assert(c.s.equals("success")); 

沒有這種同步(或東西等同,就像一個​​塊),你不能保證寫操作已經從一個線程使它到另一個(完全或以任何特定順序)。

1

在多線程應用程序中,每個CPU都有一個本地內存緩存,並且爲了優化目的,內存操作大量重新排序。您需要確保線程之間共享的C實例爲​​。這既確保了一個且只有一個線程可以執行操作它確保兩個線程都使用對象的最新內存版本。

如果您使用的是​​關鍵字,是很常見的一個final對象上進行同步:

// shared by both threads 
    final C c = new C(); 
    ... 

線程A:

... 
    // this allows us to notify on c _and_ synchronizes memory 
    synchronized (c) { 
    c.i = 10; 
    c.s = "success"; 
    // signal the other thread that is wait-ing 
    c.notify(); 
    } 

線程B:

// this allows us to wait for C _and_ synchronizes memory 
    synchronized (c) { 
    // it's common to test for wait in while loop cause of "spurious interrupts" 
    while (c.s == null) { 
     // wait for c to be updated 
     c.wait(); 
    } 
    } 
    assert(c.i == 10); 
    assert(c.s.equals("success")); 

如果ThreadA構造了C對象那麼可以改爲爲A和B定義最後的Object lock = new Object();以代替同步。您不應該在正在更改的對象上同步,因爲A和B 必須上同步對象引用以使wait/notify工作。

我試圖將提交的變量s聲明爲volatile,但它沒有幫助。

如果同時c.ic.s存在揮發性那麼這應該工作,但它會依賴於信號是如何A和B之間做它可能已經是B醒來太早了?此外,如果c對象正在更改,那麼您需要使C c本身的定義也變得不穩定。此處的​​關鍵字處理信令和內存同步。

希望這會有所幫助。

1

使用的揮發性將解決你的問題,比如你的情況,你可以有:

class C { 
    public int i; 
    volatile public String s; 
} 

聲明volatile變量是指: 這個變量的值將不會被線程本地緩存:所有讀寫將直接進入「主內存」; 對變量的訪問就好像它被包含在同步塊中一樣,同步於自身。

試試看!

相關問題