显式锁定是否会自动提供内存可见性?

2022-09-03 15:15:02

示例代码:

class Sample{
    private int v;
    public void setV(){
        Lock a=new Lock();
        a.lock();
        try{
            v=1;
        }finally{
            a.unlock();
        }
    }
    public int getV(){
        return v;
    }
}

如果我有一个线程不断调用getV,而我只在另一个线程中做一次setV,那么这个读取线程是否保证在写入后立即看到新值?还是我需要使“V”易失性或原子引用?

如果答案是否定的,那么我应该把它改成:

class Sample{
    private int v;
    private Lock a=new Lock();
    public void setV(){
        a.lock();
        try{
            v=1;
        }finally{
            a.unlock();
        }
    }
    public int getV(){
        a.lock();
        try{
            int r=v;
        }finally{
            a.unlock();
        }
        return r;
    }
}

答案 1

文档中

所有 Lock 实现都必须强制执行与内置监视器锁相同的内存同步语义:

  • 成功的锁定操作就像成功的监视器进入操作一样
  • 成功的解锁操作就像成功的监视器导出操作一样

如果在两个线程(即读取线程和写入线程)中使用,则读取线程将看到新值,因为会刷新缓存。否则,您需要声明变量以强制从读取线程中的内存读取。LockmonitorEntervolatile


答案 2

根据布莱恩定律...

如果要编写可能接下来由另一个线程读取的变量,或者读取可能上次由另一个线程写入的变量,则必须使用同步,此外,读取器和写入器必须使用相同的监视器锁进行同步。

因此,同步二传手和采集器是合适的......

如果您想避免阻塞(即同步块),请改用AtomicInteger.incrementAndGet()lock-unlock


推荐