本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
JMM第一大特性之内存可见性
变量值一旦被某个线程优先修改改变 其他线程立刻可见
对象在堆里面,整个虚拟机在内存里面
JMM三大特性
可见性例子
package com.wsx;
import java.util.concurrent.TimeUnit;
class add{
volatile int i = 1;
public void addTo20(){
this.i = 20;
}
}
public class volatileDemo {
public static void main(String[] args) {
final add add = new add();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+'\t'+add.i);//之前的值
try {
TimeUnit.SECONDS.sleep(2);//睡两秒
} catch (InterruptedException e) {
e.printStackTrace();
}
add.addTo20();//将值设置为20
},"AAA").start();
while (add.i==1){
//若不同步值则一直在此循环
}
//主线程值
System.out.println(Thread.currentThread().getName()+'\t'+add.i);
}
}
可见性
通过前面对JMM的介绍,我们知道各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作后再写回到主内存中的。
这就可能存在一个线程AAA修改了共享变量X的值但还未写回主内存时,另外一个线程BBB又对主内存中 同一个共享变量X进行操作,但此时A线程工作内存中共享变量x对线程B来说并不可见, 这种工作内存与主内存同步延迟现象就造成了可见性问题
不保证原子性:(乞丐版的sync)
1验证volatile的可见性 1.1 假如int number = 0;, number变量之前根本没有添加volatile关键字修饰,没有可见性
1.2添加了volatile, 可以解决可见性问题。
2验证volatile 不保证原子性
2.1原子性指的是什么意思?
不可分割,完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者被分割。需要整体完整 要么同时成功,要么同时失败。
2.2 volatile 不保证原子性的案例演示
class Number{
volatile int number = 0;
public void numberPlus(){
number++;
}
}
public class VolatileNoAtomic {
public static void main(String[] args) {
Number number = new Number();
for (int i = 1; i <= 20; i++) {//二十个线程
new Thread(()->{
for (int j = 1; j <= 1000; j++) {//一个线程打印2000次
number.numberPlus();
}
},String.valueOf(i)).start();
}
while (Thread.activeCount()>2){//activeCount是因为main一个线程gc一个线程然后如果这二十个线程组打印完则会小于2,故停止对main线程的休眠
Thread.yield();//Thread是main线程
}
System.out.println(Thread.currentThread().getName()+"number加后的值:"+number.number);
}
}
volatile不保证原子性理论性解释
number++底层是三个步骤
三个步骤(先拿number,然后++,然后再 放入主内存)
刚好写完又特别快,两个挂起的线程(此时已经累加过,但是没有被可见性同步,因为挂起)又被唤醒,没有拿到最新值,再一次去写(写时被挂起,也没有接到通知(可见性)),然后就出现了值覆盖现象
不保证原子性就可能出现写丢失的情况,线程太快了,后面线程会把前面的写的值覆盖
我拿的时候,我们两个拿的都是0,我正准备写回去是1的时候,突然有人捷足先登了,
我这儿被挂起,已经有人从0先写去1,而这个时候,我又马上写回去,那么相当于跟丢了一次
字节码指令集:www.cnblogs.com/taomylife/p…