正如官网上所说的ReentrantLock与sync的语义是一致的,也就是说ReentrantLock也具有一致性、可见性、原子性。
通过阅读ReentrantLoc源码可知,lock()和unlock()主要通过volatile修饰的state状态操作的。
我想问的是:ReentrantLock 是如何保证共享属性的可见性的?如下代码x变量怎么保证可见的?
int x = 0;
ReentrantLock lock = new ReentrantLock();
public void inc() {
try {
lock.lock();
x++;
} finally {
lock.unlock();
}
}
网络上给出的好多答案说:AQS中的state是volatile的,volatile为了保证可见性,会在机器指令中加入lock指令,lock强制把(工作内存)写回(主内存),并失效其它线程的缓存行(MESI),这里要注意的是,lock并不仅仅只把被volatile修饰的变量写回主内存, 而是把工作内存中的变量都写入主内存。
如上所述前部分描述没什么疑问的,但标红部分就不太理解了?volatile如果说可以把工作内存的所有数据同步回主内存,那么是不是如下代码中的y变量也能实现可见性?读取到正确的数据?
volatile int x = 0;
int y = 0;
public void inc() {
print(y);//读取y的值
y = 1;
x = 1;
}
麻烦各路大神解答啦
个人见解:假设线程A执行完"x = 1",这时x、y的值从工作内存中同步回主内存中,如果这时线程B执行y变量的打印,这时读取到的值可能是0或1,因为并不能保证线程B中y的数据会重新从主内存读取到工作内存。
ReentrantLock的加锁操作(lock())通过volatile变量(state)实现,根据volatile变量的特殊规则,读取volatile变量时会清空工作内存并重新从主内存读取,这样保证了锁中的变量都是最新值,当释放锁(unlock())时也是通过volatile变量(state)实现,根据volatile变量的特殊规则,写volatile变量时会立刻将工作内存的数据同步回主内存中,保证了主内存中数据是最新的
ReentrantLock保证数据的可见性的另一重要原因是其保证了加锁操作只能多个线程串行执行。