【问题标题】:Should I be using both lock and volatile?我应该同时使用 lock 和 volatile 吗?
【发布时间】:2014-08-12 21:25:33
【问题描述】:

我对 volatile 的理解是它确保始终从内存中读取值,因此据我所知,在以下示例中,myObject 变量需要是 volatile 以避免 NullPointerException 被提出:

private final Object lock = new Object();
private MyObject myObject = null;

//...

synchronized (lock) {
    if (myObject == null) {
        myObject = new MyObject();
    }

    myObject.blah();

    // some other stuff that I want synchronized
}

myObject 只在同步块中被触及。 lock 仅用于同步该块。

对吗?

稍微改写一下,我的问题是……想象一下有两个线程正在访问该代码。第一个线程锁定并设置 myObject,调用 .blah() 和同步块中的任何其他代码并退出同步块。这允许线程二进入同步块。如果不将 myObject 设置为 volatile,它是否仍有可能将 myObject == null 评估为 true

【问题讨论】:

  • myObject 易变吗?另外,Object lock constant 是否适用于您班级的所有实例?
  • @LuiggiMendoza - 见编辑。
  • 还有其他代码可以将myObject设置为null吗?
  • @SotiriosDelimanolis - 没想到这段代码是自包含的。
  • 我认为可能有机会,我在使用synchronized 块时没有那么愉快的经历,其中发生了意外的结果并且同步不起作用,尤其是在进程开始时。最好使用ReentrantLock。而volatile在这种情况下与同步无关,所以不需要。

标签: java locking volatile


【解决方案1】:

synchronized 块将确保其他线程可以看到对内存的更新。无需使 myObject 易失。

来自Intrinsic Locks and Synchronization

当一个线程释放一个内在锁时,一个happens-before 该行动与任何后续行动之间建立了关系 获取同一个锁。

【讨论】:

【解决方案2】:

我认为这里不需要 volatile,因为进入同步块的每个线程都在检查 myObject 引用,所以当第一个线程进入块时应该实例化 myObject,其他线程通过检查 myObject 不为空来保护。对我来说看起来不错。

编辑:我希望只有这一块您想使用 myObect 引用,并且您不要在同步块之前或之后更改此引用。

【讨论】:

  • 但是该值是否不可能存在于某处的缓存中并因此导致 NPE?
  • 没有。没有这种可能性。
  • 在您粘贴的代码中,每个线程(但当时只有一个)将检查 myObject 值,然后运行 ​​blah 方法,因此其他所有线程都会等待。但是你不能在你设置 myObject=null 的地方实现第二个块,因为那样会像你说的那样发生。如果你想将 null 设置为 myObject,你需要在一个块中完成。
猜你喜欢
  • 2021-05-18
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 2012-04-21
  • 2021-03-27
  • 1970-01-01
  • 2016-01-24
  • 2011-06-07
相关资源
最近更新 更多