20

我正在用java编写一个程序,让几辆车互相比赛。每辆车都是一个单独的线程。

当赛车完成比赛时,每一辆车都会调用这个方法。我已经以不同的计时器速度测试了该方法,它似乎工作正常。但是我确实意识到每个线程都在访问变量carsComplete,有时是在完全相同的时间(至少在日期命令给我的范围内)。

所以我的问题是:这种方法是线程安全的吗?

 public static String completeRace()
 {
      Date accessDate = new Date();
      System.out.println("Cars Complete: " + carsComplete + " Accessed at " + accessDate.toString());
      switch(++carsComplete)
      {
           case 1: return "1st";
           case 2: return "2nd";
           case 3: return "3rd";
           default: return carsComplete + "th";    
      }
 }
4

5 回答 5

28

不,您应该使用类似java.util.concurrent.atomic.AtomicInteger. 看它的getAndIncrement()方法。

于 2011-10-03T20:58:32.563 回答
9

++ 运算符不是原子的。看看这里http://madbean.com/2003/mb2003-44/。对于原子操作,您可以使用AtomicInteger

AtomicInteger atomicInteger = new java.util.concurrent.atomic.AtomicInteger(0)

每次你想增加你可以调用atomicInteger.incrementAndGet()返回原始int的方法。0 是原子整数的默认初始值。

于 2011-10-03T20:59:42.020 回答
9

预增量int不是线程安全的,使用它是AtomicInteger锁的:

AtomicInteger carsComplete = new AtomicInteger();

//...

switch(carsComplete.incrementAndGet())

顺便说一句,下面的代码也不是线程安全的。你能说出为什么吗?

carsComplete.incrementAndGet();
switch(carsComplete.get())
于 2011-10-03T20:59:56.700 回答
6

与 C++ 相同,运算符++不是原子的。

实际上,在幕后执行的指令不止 1 条(不要仅仅看到一个简单的指令就被愚弄了++i;它确实是load/add/store),并且由于在没有同步的情况下涉及超过 1 条指令,因此您可能会遇到各种交错并导致错误的结果。

如果您需要以carsComplete线程安全的方式增加,您可以使用 java 的构造AtomicInteger,或者您可以同步整个方法

于 2011-10-03T21:04:59.350 回答
3

问题是“预增量运算符线程安全吗?”</p>

答:没有,为什么?因为涉及的指令数量。Atomic 表示单个操作,这里需要执行加载/添加/存储操作。所以不是原子操作。

  Same for post increment.
于 2015-06-10T04:51:45.937 回答