volatile 修饰的共享变量,有两点特性
保证了不同线程对该变量操作的内存可见性
禁止指令重排序
java 中 所有的变量都存在主存中,每个线程又有自己的工作内存,
线程操作以工作内存为主,只能访问自己的工作内存,之后要把值同步到主内存中,
在执行的时候线程回去主存中读数据,然后加载到工作内存中,然后执行完在把值创给主存,主存的值就会更新
并发的三个特性:
原子性:表示操作不可终端,要么一定执行完,要么不执行
可见性:指的是一个线程修改数据,其他线程立刻能访问到
有序性:即程序执行的顺序按照代码的先后顺序执行
volatile :
是当变量修饰成volatile的时候,当读变量的时候,总是读到他的最新的值,不管那个线程对变量进行了写操作,都会立刻更新到主存中,
他保证了可见性和有序性,volatile限制了指令的重排序
当读一个volatile变量时,会把线程对于本地的内存置为无效,线程接下来将从主存中读取共享变量
但是他无法保证原子性,因为多个线程读去变量的时候,可能会被阻塞,
假设A读取值为10,被阻塞,B读取然后+1,就会变成11,
而因为A以及读到了数据,就不会去读最新的
volatile 底层机制:
在生成汇编代码的时候会在volatile关键字的代码之前会有一个lock指令
它保证了,重排序的时候不能把后面指令重排序到这个位置之前
会把cache写入内存
写入动作会使别的内存无效cache,相当于让别的线程去读新写入的数值
使用场景:
状态标记变量,因为对于标记变量只有赋值和读取,没有数据增加减少操作,会比上锁有一定效率提升
单例模式里面的双重检查锁定,可以用它来修饰,因为也是只涉及到了读取它的状态
双重检查 ->多线程
如果你要共享的资源发生互斥的时候 并且是有判断什么时候结束
可以在已有锁的外面再加上一个上述的判断
这样当你已经满足这个判断的时候已经不用在进入锁住块的内部了
这样其他的线程在锁外的判断即满足 而不是在锁住等待了
可以提高效率
但是这样还是有瑕疵
但是这个方法还是有问题的因为你创建变量 new 这个对象的时候 这个变量又可能还是null
当有一个线程正好到new 这个对象的时候 你突然来一个线程调用这个方法
这个时候上一个线程 new了这个对象 但是还没完全初始化构造函数的时候
第二个线程会判断有这个对象 返回 然后第一个线程回来 发现还没new 利索
继续new 这个时候 两个对象还是不一样地址
如果觉得有什么疑惑或者博主代码有什么问题,可以通过关于我,加我QQ联系 ,感谢。