2010-12-16 72 views
0

下面的代碼不應該輸出正確的餘額(100),但它每次都打印出100次。這是爲什麼?下面的代碼似乎不是線程安全的。Java線程問題

public class ThreadObject implements Runnable{ 

    private int balance; 

    public ThreadObject() { 
     super(); 
    } 

    public void add() { 
     int i = balance; 
     balance = i + 1; 
    } 

    public void run() {  
     for(int i=0;i<50;i++) { 
      add(); 
      System.out.println("balance is " + balance); 
     } 
    } 

} 

public class ThreadMain { 

    public static void main(String[] args) { 

     ThreadObject to1 = new ThreadObject(); 
     Thread t1 = new Thread(to1); 
     Thread t2 = new Thread(to1); 
     t1.start(); 
     t2.start(); 

    } 
} 

如果下面的代碼確實是線程安全的,你能解釋一下嗎?

因爲它看起來像add()中的代碼根本不是線程安全的。一個線程可能會將i設置爲當前balance,但隨後在第二個線程接管並更新balance時變爲非活動狀態。然後,線程1醒來,將balance設置爲過期的i加1.

回答

1

println可能比更新餘額的代碼慢數千倍。每個線程幾乎花費所有時間打印,因此它們同時更新餘額的可能性非常小。

在閱讀i和寫作i + 1之間添加一個小睡眠。

下面是一個卑鄙的問題:運行上面的代碼後i的最小可能值是多少?

+0

是最小值50嗎? 因爲我能想到的最糟糕的情況是T1會睡覺,T2會接管並更新我,T1會喚醒並更新平衡,T2會喚醒並更新平衡......並繼續處於此模式。 還是有比這更糟的情況? – Glide 2010-12-16 10:51:51

+0

@Glide:不,它少得多。 – 2010-12-16 11:59:13

+0

我似乎無法弄清楚。你能解釋一下嗎? – Glide 2010-12-16 23:17:27

0

將您的println稍微移動一下,看看它是不是線程安全的。如果仍然看不到任何變化,請將50放大(如5000或更多)。

public void add() { 
    int i = balance; 
    System.out.println("balance is " + balance); 
    balance = i + 1; 
} 

public void run() {  
    for(int i=0;i<50;i++) { 
     add(); 
    } 
}