简体   繁体   English

Java在原子操作上同步

[英]Java synchronized on atomic operation

Is this Java class thread safe or reset method needs to be synchronized too? 这个Java类线程安全还是重置方法也需要同步? If yes can someone tell me the reason why? 如果可以,有人可以告诉我原因吗?

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

Not without synchronizing rest() and adding more methods. 并非没有同步rest()并添加更多方法。 You will run into cases where you will need more methods. 您将遇到需要更多方法的情况。 For example 例如

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
}

To fix the above you need something like 要解决上述问题,您需要

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

Instead, use Java's bulit-in class AtomicInteger which covers all cases. 相反,请使用Java的覆盖类AtomicInteger,该类涵盖所有情况。 Or if you are trying to learn thread safety then use AtomicInteger as a standard (to learn from). 或者,如果您尝试学习线程安全性,请使用AtomicInteger作为标准(以供学习)。

For production code, go with AtomicInteger without even thinking twice! 对于生产代码,无需三思而后行即可使用AtomicInteger! Please note that using AtomicInteger does not automatically guarantee thread safety in your code. 请注意,使用AtomicInteger不能自动保证代码中的线程安全。 You MUST make use of the methods that are provided by the api. 您必须使用api提供的方法。 They are there for a reason. 他们在那里是有原因的。

Note that synchronized is not just about mutual exclusion, it is fundamentally about the proper ordering of operations in terms of the visibility of their actions. 请注意, synchronized不仅相互排斥,而且从根本上来说,还涉及从操作的可见性方面对操作进行正确排序。 Therefore reset must be synchronized as well, otherwise the writes it makes may occur concurrently to other two methods, and have no guarantee to be visible. 因此, reset必须同步,否则其他两种方法可能同时发生reset ,并且不能保证可见。

To conclude, your class is not thread-safe as it stands, but will be as soon as you synchronize the reset method. 总而言之,您的类不是当前的线程安全的,但是将在您同步reset方法后立即执行。

You have to synchronize your reset() method also. 您还必须同步您的reset()方法。

To make a class thread safe you have to synchronize all paths that access a variable else you will have undesired results with the unsynchronized paths. 为了使class线程安全,您必须同步访问变量的所有路径,否则您将获得不期望的结果以及未同步的路径。

You need to add synchronized to reset method too and then it will be synchronized. 您还需要添加同步重置方法,然后它将被同步。 But in this way you achieve syncronization through locks, that is, each thread accesing the method will lock on the NamedCounter object instace. 但是通过这种方式,您可以通过锁定来实现同步,也就是说,访问该方法的每个线程都将锁定NamedCounter对象实例。

However, if you use AtomicInteger as your count variable, you don't need to syncronize anymore because it uses the CAS cpu operation to achieve atomicity without the need to synchronize. 但是,如果将AtomicInteger用作计数变量,则不再需要同步,因为它使用CAS cpu操作来实现原子性而无需同步。

Not an answer, but too long for a comment: 不是答案,但是评论太久了:

If reset() is synch'ed, then the 0 become visible to any thread that reads or increments the counter later. 如果将reset()同步,则任何稍后读取或递增计数器的线程都将看到0。 Without synchronization, there is no visibility guarantee. 没有同步,就无法保证可见性。 Looking at the interaction of concurrent increment and the unsychronized reset, it may be that 0 becomes visible to the incrementing thread before entering the method, then the result will be 1. If counter is set to 0 between increment's read and write, the reset will be forgotten. 查看并发增量和非同步复位的相互作用,可能是增量线程在进入方法之前可以看到0,那么结果将是1。如果在增量的读和写之间将计数器设置为0,则复位将被遗忘。 If it is set after the write, the end result will be 0. So, if you want to assert that for every reading thread, the counter is 0 after reset, that method must be synchronized, too. 如果在写操作后将其设置,则最终结果将为0。因此,如果要断言每个读取线程的计数器在复位后均为0,则该方法也必须同步。 But David Schwartz is correct that those low-level synchronizations make little sense whithout higher-level semantics of those interactions. 但是David Schwartz是正确的,如果没有这些交互的高级语义,那么这些低级同步就毫无意义。

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

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