【Java并发(六)】--Java内存模型之锁的内存语义

2018-11-16  本文已影响0人  小安的大情调

如未作特殊说明,文章均为原创,转发请注明出处。

[TOC]

前言

​ 上篇文章详细分析了volatile的内存语义,并且介绍了是如何实现线程之间通信,可见性。保证单个操作下的volatile变量的原子性。并且将其的内存语义与锁做了对比。那么本章就来详细的分析锁的内存语义。


锁的内存语义

​ 一提到锁,大家自然而然地想到前面分析过地synchronized关键字。 它是JAVA并发编程中最重要地同步机制。锁可以让临界区(同步块)互斥(独占锁)。下面来分析以下锁地另一个同样非常重要地锁地内存语义。

锁地释放-获取建立的happens-before关系

​ 通过一段代码来具体地分析以下锁地释放和获取建立的happens-before关系。

public class MonitorExample{
    int a = 0;
    public synchronized void write(){   // 1
        a++;                            // 2
    }                                   // 3
    public synchronized void read(){    // 4
        int i = a;                      // 5
    }                                   // 6
}

假设线程A执行write()线程B执行read(),两个方法都使用synchronized进行同步,并且锁对象是同样的(两个线程同一把锁),那么很显然,如果线程A先执行,那么线程B只能等到线程A执行完之后释放锁,获取锁之后才能真正的执行read()

​ 那么可以得出结论是:

根据锁的获取跟释放关系 : 3 happens-before 4

根据happens-before的传递性: 2 happens-before 5

这里可以推测出,当线程A释放锁的同时,所有锁内的共享变量将对线程B可见。(类似于volatile的内存语义)这种操作也可以看作两个不同的线程通过主内存来通信。实现共享变量在多线程下的原子性。

锁的释放-获取的内存语义

​ 当线程A释放锁时,会将修改后的变量刷新到主内存,那B线程在拿到锁后会将本地内存缓存的值置为无效,那么在临界代码块中的共享变量就必须要从主内存中重新获取。

线程A将新的数据刷新到主内存,并且释放锁,等待线程B获取锁!
在线程A执行完后,所有等待这把锁的线程的本地内存缓存的数据都会被置为无效,在线程B执行的时候,必须重新在主内存中读取。
线程B在获取锁之后,可重新读取共享变量
这样看来锁的释放-获取内存语义volatile的写-读内存语义有异曲同工之处。

下面给锁的获取-释放内存语义做个小的总结

锁的释放-获取内存语义小结

锁内存语义的实现

​ 这里等深入了解了AQSjava同步框架AbstractQueuedSynchronizer。

上一篇 下一篇

猜你喜欢

热点阅读