简体   繁体   English

同步保证线程是否会看到另一个线程修改的非易失性变量的最新值?

[英]Does synchronized guarantee a thread will see the latest value of a non-volatile variable being modified by another thread?

Here is a simple example: 这是一个简单的例子:

private long counter = 0;

// note this method is NOT synchronized
// this will be called by thread A
public void increment() { counter++; }

// note this method IS synchronized
// this will be called by thread B
public synchronized long value() { return counter; }

So I just want to get a good value for counter , not a stuck value in the cpu cache because the variable is non-volatile. 所以我只想为counter获得一个好的值,而不是cpu缓存中的卡值,因为该变量是非易失性的。 The goal is to NOT make counter volatile so it does NOT impact thread A doing the increments, but only thread B, which I don't care, when it reads the variable. 目标是不使计数器变为易失性,因此它不会影响线程A执行增量,但只有线程B,我不关心,当它读取变量时。

Just for the record, I plan to read the value of counter from thread B when thread A has already finished anyways... 只是为了记录,我计划在线程A已经完成时从线程B读取counter的值...

long assignment is not guaranteed to be atomic, so not only could B read a stale value, it could also read a half written value. long赋值不保证是原子的,所以不仅B可以读取过时的值,它还可以读取一半的写入值。

For proper visibility you need to make counter volatile. 为了获得适当的可见性,您需要使计数器易变 Note that even then, calling increment n times from several threads may not increment counter by n. 请注意,即使这样,从多个线程调用增量n次也不能将计数器增加n。

You could use an AtomicLong to simply since your problem. 您可以使用AtomicLong来解决问题。

No, the synchronized block in thread B does not ensure that it will read the actual current value of counter . 不,线程B中的同步块不能确保它将读取counter的实际当前值。 You would need synchronized blocks in both threads to do that. 您需要两个线程中的同步块才能执行此操作。 From a practical perspective, your code ensures that the processor running thread B invalidates its cache and reads the value of counter from main memory, but it does not ensure that the processor running thread A flushes its current value to main memory, so the value in main memory may be stale. 从实际角度来看,您的代码确保运行线程B的处理器使其缓存无效并从主内存中读取counter的值,但它不能确保运行线程A的处理器将其当前值刷新到主内存,因此值为主存可能陈旧。

Since using a volatile variable is cheaper than synchronized blocks in both threads, making counter volatile is likely the correct solution. 由于使用volatile变量比两个线程中的同步块便宜,因此使counter易失性可能是正确的解决方案。 This is what volatile variables are for. 这是volatile变量的用途。

Edit: if thread A is going to complete before thread B reads the final value, you could enclose the entire execution of thread A in a single synchronized block or have thread B join thread A before reading the counter, ensuring that thread A completes before the counter is read. 编辑:如果线程A在线程B读取最终值之前完成,则可以将线程A的整个执行包含在单个同步块中,或者让线程B在读取计数器之前连接线程A,确保线程A在完成之前完成计数器被读取。 That would result in one cache flush at the end of Thread A's execution, which would have negligible impact on performance. 这将导致在线程A执行结束时一次缓存刷新,这对性能的影响可以忽略不计。

No, synchornized only guarantees visibility of changes that were made within synchronized blocks of the same lock: 不, synchornized仅保证在同一锁的同步块内进行的更改的可见性:

synchornized(this) {
    counter++;
}

or before them (as defined by transitive nature of happens-before relationship): 或者在它们之前(由关系之前发生的传递性质定义):

// Thread A
counter++
synchronized (this) {
    finished = true; 
}

// Thread B
synchonized (this) {
    if (finished) {
        // you can read counter here
    }
}

Note, however, that counter is guaranteed to be visibile if you read it after you positively determined that Thread A has finished (for example, using join() ): 但请注意,如果在确定线程A已完成(例如,使用join() )之后读取它,则保证counter是可见的:

threadA.join();
// you can read counter here

No.There is no guarantee that Thread B will gives latest value always.Since increment() is non-synchronized method and value() is synchronized method. 不能保证Thread B总是给出最新值。由于increment()是非同步方法,value()是同步方法。
Since 以来

While a thread is inside a synchronized method of an object, all other threads that wish to execute this synchronized method or any other synchronized method of the object will have to wait. 当一个线程在一个对象的synchronized方法中时,所有其他希望执行这个synchronized方法或该对象的任何其他同步方法的线程都必须等待。

This restriction does not apply to the thread that already has the lock and is executing a synchronized method of the object. 此限制不适用于已具有锁定并正在执行对象的同步方法的线程。 Such a method can invoke other synchronized methods of the object without being blocked. 这种方法可以调用对象的其他同步方法而不会被阻塞。 The non-synchronized methods of the object can of course be called at any time by any thread. 当然,任何线程都可以随时调用对象的非同步方法。

暂无
暂无

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

相关问题 非易失性变量是否需要同步? - Does a non-volatile variable need synchronized? 是否可以修改非易失性变量,以便另一个线程能够“看到”更新? - Is it possible to modify a non-volatile variable such that another thread is able to “see” the update? 在从另一个线程读取期间是否可以读取非易失性变量的陈旧值? - Is it possible to read stale value of non-volatile variable during read from another thread? 对非易失性字段的同步访问是否安全? - Is synchronized access to non-volatile fields thread safe? 具有非易失性布尔变量的 Thread.sleep 行为 - Thread.sleep behaviour with non-volatile boolean variable 由该类的方法延迟分配的非易失性变量不能被另一个线程读取吗? - Can a non-volatile variable that is delayed assigned to by a method of the class not be read by another thread? 线程何时从主内存而不是工作内存中读取非易失性变量? - When does Thread read a non-volatile variable from main memory instead of working memory? java,什么时候(以及多长时间)线程可以缓存非易失性变量的值? - java, when (and for how long) can a thread cache the value of a non-volatile variable? 是否保证在另一个线程中看到一个线程中的非易失性成员变量的赋值? - Are assignments to non-volatile member variables in one thread guaranteed to be seen in another thread? 非易失性字段+来自另一个线程的第一个对象访问(java) - Non-volatile fields + first object access from another thread (java)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM