2010-12-16 79 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(); 
    } 
}