java多线程访问原始变量

时间:2010-07-22 18:05:46

标签: java multithreading primitive-types

我知道同时从不同的线程访问同一个对象,没有同步,通常是一件坏事。但是这个案子呢:

我有多个线程在运行(考虑两个,ThreadA和ThreadB)。我也有这个静态类来保持Thread执行某些操作的次数。

public class Counter {
  static private int counter=0;
  static public void incCounter() {
    counter++;
  }
}

如果ThreadA和ThreadB都调用Counter.incCounter()?

会发生什么

5 个答案:

答案 0 :(得分:11)

这不安全。

每个线程都会尝试读取counter,向其中添加一个,然后回写结果。您无法保证这些读取和写入的顺序,或者即使结果对每个线程都可见。

特别是,一个失败的情况是每个线程读取值0,将其递增为1,并写回值1.即使在两个线程尝试递增它之后,这也会使计数器的值为1。

请考虑使用AtomicInteger。incrementAndGet()代替。

答案 1 :(得分:1)

它的值可以是1或2.在这种情况下,静态和非静态变量之间没有区别。

答案 2 :(得分:0)

无论是静态对象还是实例都无关紧要:如果从多个线程更改它,就会出现问题。

答案 3 :(得分:0)

避免冲突使用关键字synchronized。

public class Counter {
  static private int counter=0;
  public static synchronized void incCounter() {
      counter++;
  }
}

此关键字只允许一个时间线程调用incCounter()。

答案 4 :(得分:0)

Dave是正确的,但快速修复只是将“synchronized”关键字添加到该方法描述中;如果多个线程调用该方法,它们将在方法边界处阻塞,直到内部的一个(赢得比赛)增加并存在,然后第二个调用者将进入。

这就像在Singleton类上设计一个好的“getInstance()”方法一样;你通常希望它被同步,所以你没有2+个线程进入方法的情况,ALL看到“instance”为null,然后ALL创建一个新实例,将它分配给本地成员并返回它

在这种情况下,您的线程可能会以“相同”实例的不同引用结束。因此,您同步代码块,只允许第一个线程创建实例(如果它为null),否则始终将相同的实例返回给所有调用者。

if(instance == null)检查加上回报便宜;对于将来调用getInstance(或者在你的示例中为incCounter),我相信微秒的顺序,所以如果你需要,不需要回避synchronized关键字;这就是它的用途。

话虽如此,如果你不能节省微秒......那么你可能会使用错误的语言:)