从happen-before角度分析synchronized与lock的内存可见性问题

充电时刻(happen-before八个原则)


  • 程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
  • 监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。
  • volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
  • 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。

  • start()规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。
  • Join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。
  • 程序中断规则:对线程interrupted()方法的调用先行于被中断线程的代码检测到中断时间的发生。
  • 对象finalize规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的finalize()方法的开始。

推荐阅读: java 8大happen-before原则超全面详解

happen-before不能理解成在什么之前发生,它和时间没有任何关系,解释成“生效可见于” 更准确。即使出现了指令重排,只要符合happen-before规则,那么上文的结果就会对下文生效。

关于内存可见性的疑惑

一个简单的例子

    private static int count;

    public void incr() {
        //加锁
        while(count <= 100) {
            count++;
        }
        //解锁
    }

不知道大家有没有像我一样的疑惑,无论是使用哪种加锁方式,count变量并没有被volatile修饰,那么对count变量的修改是如何保证内存可见性的呢?

好像对这件事是如此的理所应当,就像太阳每天从东方升起,不觉得这有什么好质疑的。

lock的内存可见性

以ReentrantLock公平锁为例,我们看看获取锁 & 释放锁的关键代码

    private volatile int state;

    protected final int getState() {
        return state;
    }

    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        //重要
        int c = getState(); //line 1
        //...竞争锁逻辑忽略
    }

    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        // ...根据状态判断是否成功释放,省略

        //写volatile变量,重要
        setState(c); // line 2
        return free;
    }

假设有A,B两个线程执行count++,A线程抢到执行权,B线程阻塞。A线程释放锁时会走line 2,这时B线程继续争抢执行权执行line 1。

  • 对一个volatile域的写,happens-before于任意后续对这个volatile域的读。

    A线程释放锁setState一定生效可见于B线程获取锁getState

  • 一个线程中的每个操作,happens-before于该线程中的任意后续操作。

    A线程的count++一定生效可见于A线程解锁

  • 如果A happens-before B,且B happens-before C,那么A happens-before C。

    A线程的count++一定生效可见于B线程获取锁getState以及后续的业务处理

synchronized的内存可见性

  • 对一个锁的解锁,happens-before于随后对这个锁的加锁。

    A线程的解锁一定生效可见于B线程获取锁,后续流程分析与lock一致。

你可能感兴趣的:(从happen-before角度分析synchronized与lock的内存可见性问题)