java内存模型之synchronized、volatile关键字

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32711825/article/details/79796548

一、概念

Java内存模型(Java Memory Model):描述了Java程序中各种变量(主要指线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。

工作内存:

主内存:

共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。

可见性:一个线程对共享变量值的修改,能够及时的被其他线程看到。

二、JVM规范中的两条规定

1.线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主存中读写。

2.不同的线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。

三、实现可见性

1.线程修改后的共享变量值能够及时从工作内存刷新到主内存中

2.其他线程能够及时把贡献变量的最新值从主内存更新到自己的工作内存中去。

四、Java语言层面实现可见性

1.synchronized实现了原子性(同步)和可见性

(1)线程解锁前,必须把共享变量的最新值刷新到主内存中。

(2)线程加锁时,将清空工作内存中的共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值。

ps:加锁和解锁的是同一把锁。synchronized的加锁和解锁保证了锁内的代码不会因为指令重排而导致的不可见性的问题。

2.volatile能够保证可见性,不能保证变量复合操作的原子性

volatile变量的读写是通过加入内存屏障和禁止指令重排来实现的内存可见性。具体来说就是: 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令,使当前共享变量从工作内存写到主内存;对volatile变量的读操作时,会在读操作前加入一条load屏障指令,使当前共享变量从主内存读到工作内存。

关于主内存和工作内存的交互,JVM提供了8条指令来完成,load,store只是其中的两条。

volatile不能保证变量复合操作的原子性:比如 i++操作(i是volatile变量); 这个指令包含三步操作:

1.从主存中读取i的值到工作内存

2.i的值加1

3.i的最新值从工作内存写入主内存

volatile不能保证这三步操作是一个原子操作。可以通过jdk1.5中的lock来保证volatile变量复合操作的原子性问题。

lock.lock();

try{

    i++; 

}finally{

    lock.unlock();

}

备注:

指令重排

猜你喜欢

转载自blog.csdn.net/qq_32711825/article/details/79796548