简体   繁体   English

我需要使用易失性吗?

[英]Do I need to use volatile?

Consider the following code:考虑以下代码:

public class MyDataStructure {

    int size;
    final ReentrantLock lock = new ReentrantLock();

    public void update() {
        lock.lock();
        try {
            // do coll stuff
            size++;
        } finally {
            lock.unlock();
        }
    }

    public int size() {
        return size;
    }
}

As far as I understand, ReentrantLock imposes an happens-before relationship so size++ needs to affect the main memory and the cache (of other threads) with the new value.据我了解, ReentrantLock强加了先发生关系,因此size++需要用新值影响主 memory 和缓存(其他线程)。 Hence, no need to use volatile for size .因此,不需要使用volatile作为size Also, for the same reason the method size() can simply return size .此外,出于同样的原因,方法size()可以简单地返回size

Is my understanding correct?我的理解正确吗?

No.不。

Other threads may see a stale (old) value of size.其他线程可能会看到过时的(旧)大小值。

When other threads execute size() there is nothing there instructing it to ensure it's not reading an old value, such as a locally cached value in another cpu cache etc. Also worth mentioning is hoisting by the jvm.当其他线程执行size()时,没有任何内容指示它确保它不读取旧值,例如另一个 cpu 缓存中的本地缓存值等。另外值得一提的是 jvm 的提升。

AN example, if you have a loop calling size() in one thread, it may never exit if update() is not called in the loop, or size changed, and called/changed from other threads only.一个例子,如果你有一个循环调用size()在一个线程中,如果update()没有在循环中调用,或者大小改变,并且只从其他线程调用/改变,它可能永远不会退出。

while (size() == 0) {
   ...
}

The jit compiler, (at least the modern part what used to be called the c2/server compiler) could happily optimize away (hoist) the size variable checks as it sees that it never changes in the loop. jit 编译器(至少是过去称为 c2/server 编译器的现代部分)可以愉快地优化(提升)大小变量检查,因为它看到它在循环中永远不会改变。

As far as I understand, ReentrantLock imposes an happens-before relationship...据我了解, ReentrantLock 强加了一种先发生的关系......

Yes.是的。 When some thread W (W for "writer") unlocks a lock, that "happens before" some other thread R (for "reader") subsequently locks the same lock.当某个线程 W(W 代表“writer”)解锁一个锁时,“发生在”某个其他线程 R(代表“reader”)随后锁定同一个锁。

In order to take advantage of that relationship, you have to lock the same lock in both methods:为了利用这种关系,您必须在两种方法中锁定相同的锁:

public class MyDataStructure {

    int size;
    final ReentrantLock lock = new ReentrantLock();

    public void update() {
        lock.lock();
        try {
            size++;         // happens before unlock() because things that happen
                            //  in one thread all happen in _program order._
        } finally {
            lock.unlock();  // Happens before a pending lock.lock() call in some
                            //  other thread.
        }
    }

    public int size() {
        lock.lock();        // Happens before return size because...
                            //  ...program order.
        try {
            return size;
        } finally {
            lock.unlock();
        }
    }
}

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

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