首页 > JVM > java内存模型与volatile关键词

java内存模型与volatile关键词

作者:bin

java的内存模型

线程工作内存中保存的都是该变量的副本,线程对变量对操作都是对工作内存中操作,而不是直接改主内存,最后更新到主内存中

volatile

我们知道(保证可见性、有序性)有2个能力,1个注意点:
1.保证变量可见性
2.禁止指令重排
3.不保证原子性

1.可见性
我知道java的变量都是存在堆内存中的,线程的本地方法栈存的是引用和基本类型的副本。
那么一个基本类型实际上是在「主内存」和「工作内存」中都有
线程修改时是先修改「工作内存」再同步至「主内存」。
线程读取时是先从「工作内存」读取

volatile关键词就是做了2件事情:
1.当写volatile变量时立即同步至「主内存」,
2.当读volatile变量时,将「工作内存」这个变量置为失效,即从「主内存」直接读取

2.禁止指令重排
这个可以参考单例模式中的饿汉模式
如果出现指令重排,可能会出现如下情况,即未初始化,就将引用指向完成,那么其他线程读取到Singleton!=null的,但是实际上还未初始化完成,就会出现线程安全问题:

memory = allocate(); //1.分配对象内存空间
instance = memory;   //3.设置instance指向刚分配的内存地址,此时instance!=null,但是对象还没有初始化完成!
instance(memory);    //2.初始化对象

作为参考,正常顺序是:

memory = allocate(); //1.分配对象内存空间
instance(memory);    //2.初始化对象
instance = memory;   //3.设置instance指向刚分配的内存地址,此时instance!=null

3.不保证原子性
例如自增,实际上是先获取,再+1,并非原子性操作,会出现线程安全问题:

public static int count =0;
public synchronized static void inc(){
  count++;
}

例如true、false判断,不需要保证原子性,但要保证可见性

volatile boolean isEnd;
while (!isEnd){
 System.out.println("isEnd");
}

您必须 [ 登录 ] 才能发表留言!