为什么运行时会出现此方法的不一致

时间:2016-11-17 12:01:58

标签: java concurrency java.util.concurrent

有时候变量总数将等于运行时的其他东西而不是50005000它总是很短,如50005001,有时为什么这种情况发生时不应该同步(这)创建一个只能更新一次的锁锁是由线程释放的吗?

import java.util.concurrent.atomic.AtomicLong;

public class CurrentThread {
    public static AtomicLong c = new AtomicLong(0L);
    public static AtomicLong total = new AtomicLong(0L);
    public static void main(String[] args) {

        Thread t = Thread.currentThread();
        System.out.println(t);
        t.setName("My Thread");
        System.out.println(t);

        for (int x = 0; x < 10; x++) {
            System.out.println("Instance " + x);
            new Thread(new Updater(x, "Thread: " + String.valueOf(x))).start();
        }
        try {
            Thread.sleep(1000);
        }
        catch (InterruptedException e) {
        }    
    }
}
class Updater implements Runnable {
    public int na;   
    private String threadName;  
    public Updater(int n, String threadName) {
        this.na = n;
        this.threadName = threadName;  
    }  
    @Override
    public void run() {
        this.updateCount();
        if(CurrentThread.total.get() == 50005000) {
            System.out.println("Passed");
        }
        else {
            System.out.println("Failed");
        }
    }    
    public  void  updateCount() {

            while (CurrentThread.c.get() < 10000) {
                synchronized(this) {
                    CurrentThread.c.getAndIncrement();
                    CurrentThread.total.addAndGet(CurrentThread.c.get());
                    System.out.println(this.threadName + " " + String.valueOf(CurrentThread.c.get()) + " " + CurrentThread.total.get() + " " + System.nanoTime());
                }
            }
      }  
}

1 个答案:

答案 0 :(得分:4)

您在this上进行同步,因为每个线程都有一个不同的Runnable实例,所以它实际上根本没有同步。

对所有Updater个实例之间共享的内容进行同步,例如: Updater.class

但是请注意,AtomicLong上的同步有点代码味道 - 它本来就意味着原子地做事。

您可以改为使用compareAndSet,并避免完全同步,例如:

while (CurrentThread.c.get() < 10000) {
  while (true) {
    long currValue = CurrentThread.c.get();
    if (currValue >= 10000) break;

    long newValue = currValue + 1;

    // Only sets c to newValue if its value is still currValue.
    if (CurrentThread.c.compareAndSet(currValue, newValue)) {
      long total = CurrentThread.total.addAndGet(newValue);
      System.out.println(
          this.threadName + " " + newValue + " " + total + " " + System.nanoTime());
      break;
    }
  }
}

请注意,这会使用&#34;已知&#34;值,例如newValuetotal,而不是从AtomicLong再次获取它们。