Java-锁的内存语义

锁是Java并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程获取同一个锁的线程发送消息。

一、锁的释放和获取的内存语义

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。

当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。

对比锁释放-获取的内存语义与volatile写-读的内存语义可以看出:锁释放与volatile写有相同的内存语义;锁获取与volatile读有相同的内存语义。

线程A释放一个锁,实质上是线程A向接下来将要获取这个锁的某个线程发出了(线程A对共享变量所做修改的)消息。

线程B获取一个锁,实质上是线程B接受了之前某个线程发出的(在释放这个锁之前对共享变量所做修改的)消息。

线程A释放这个锁,随后线程B获取这个锁,这个过程实质上是线程A通过主内存向线程B发送消息。

二、锁内存语义的实现

在ReentrantLock中,调用lock()获取锁;调用unlock()方法释放锁。

ReentrantLock的实现依赖于Java同步器框架AbstractQueueSynchronizer(AQS)。AQS使用一个整型的volatile变量(state)来维护同步状态,这个volatile变量是ReentrantLock内存语义实现的关键。

使用公平锁时,加锁方法lock()调用轨迹如下:

1)ReentrantLock:lock()

2)FairSync:lock();

3)AbstractQueuedSynchronizer:acquire(int arg)

4)ReentrantLock:tryAcquire(int acquires)

解锁unlock()调用轨迹

1)ReentrantLock:unlock

2)AbstractQueueSynchronizer:release(int arg)

3)Sync:tryRelease(int release)

三、concurrent包的实现

Java线程通信有下面4种方式:

1)A 线程写volatile变量,随后B线程读这个volatile变量

2)A线程写volatile变量,随后B线程用CAS更新这个volatile变量

3)A线程用CAS更新一个volatile变量,随后B线程用CAS更新这个volatile变量

4)A线程用CAS更新一个volatile变量,随后B线程读这个volatile变量

通用化的的实现模式

首先,声明共享变量为volatile

然后,使用CAS的原子条件更新来实现线程之间的同步

同时,配合以volatile的读/写和CAS所具有的volatile读和写的内存语义实现线程之间的通信。

猜你喜欢

转载自blog.csdn.net/cclliii/article/details/82824699