繁体   English   中英

Java在原子操作上同步

[英]Java synchronized on atomic operation

这个Java类线程安全还是重置方法也需要同步? 如果可以,有人可以告诉我原因吗?

public class NamedCounter {
   private int count;
   public synchronized void increment() { count++; }
   public synchronized int getCount() { return count; }
   public void reset() { count = 0; }
}

并非没有同步rest()并添加更多方法。 您将遇到需要更多方法的情况。 例如

NamedCounter counter = new NamedCounter();
counter.increment();
// at this exact time (before reaching the below line) another thread might change changed the value of counter!!!!
if(counter.getCount() == 1) {
    //do something....this is not thread safe since you depeneded on a value that might have been changed by another thread
}

要解决上述问题,您需要

NamedCounter counter = new NamedCounter();
if(counter.incrementAndGet()== 1) { //incrementAndGet() must be a synchronized method
    //do something....now it is thread safe
}

相反,请使用Java的覆盖类AtomicInteger,该类涵盖所有情况。 或者,如果您尝试学习线程安全性,请使用AtomicInteger作为标准(以供学习)。

对于生产代码,无需三思而后行即可使用AtomicInteger! 请注意,使用AtomicInteger不能自动保证代码中的线程安全。 您必须使用api提供的方法。 他们在那里是有原因的。

请注意, synchronized不仅相互排斥,而且从根本上来说,还涉及从操作的可见性方面对操作进行正确排序。 因此, reset必须同步,否则其他两种方法可能同时发生reset ,并且不能保证可见。

总而言之,您的类不是当前的线程安全的,但是将在您同步reset方法后立即执行。

您还必须同步您的reset()方法。

为了使class线程安全,您必须同步访问变量的所有路径,否则您将获得不期望的结果以及未同步的路径。

您还需要添加同步重置方法,然后它将被同步。 但是通过这种方式,您可以通过锁定来实现同步,也就是说,访问该方法的每个线程都将锁定NamedCounter对象实例。

但是,如果将AtomicInteger用作计数变量,则不再需要同步,因为它使用CAS cpu操作来实现原子性而无需同步。

不是答案,但是评论太久了:

如果将reset()同步,则任何稍后读取或递增计数器的线程都将看到0。 没有同步,就无法保证可见性。 查看并发增量和非同步复位的相互作用,可能是增量线程在进入方法之前可以看到0,那么结果将是1。如果在增量的读和写之间将计数器设置为0,则复位将被遗忘。 如果在写操作后将其设置,则最终结果将为0。因此,如果要断言每个读取线程的计数器在复位后均为0,则该方法也必须同步。 但是David Schwartz是正确的,如果没有这些交互的高级语义,那么这些低级同步就毫无意义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM