这是我参与「掘金日新计划 · 6 月更文挑战」的第11天 ,点击查看活动详情
JMM: java memory model (java内存模型)
抽象的内存模型--不存在;
volatile :
保证可见性,不保证原子性(synchronized保证),
禁止指令重排-(不让插队--保证有序)
所以就是volatile的java虚拟机的轻量级的同步机制
一、可见性
若是某一个线程改变了一个固定的变量,其他线程会立刻知晓;
也就是及时通知
//volatile可以保证可见性:
及时的通知其他线程,主物理内存中的值已经被修改;
import java.util.concurrent.TimeUnit;
class volatileTest1{
//加volatile可以看见结果
volatile int number=0;//成员变量默认为0
public void addTo60(){
//将number变成60
this.number=60;
}
}
public class volatileDemo {
//如何理解这个volatile的保证可见性:
/*
* 可见性: 保证在线程使用的过程中,将数据修改后,及时的通知其他线程更新数据;
*
* demo的设计原理: (需要添加的是一个睡眠时间3-不然结果会出错误)
* 我们运行nto60的方法--看main线程是否能获得已经变化了的数值number
* 否则将循环下去
* */
public static void main(String[] args) {
//1.资源类的初始化
volatileTest1 volatileTest1=new volatileTest1();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+":come in"+volatileTest1.number);
//这里必须要睡3秒--不然的结果就是main线程也会同步,因为线程的运行速度太快啦
try {
//休眠3秒钟
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
//2.操作高内聚的方法nTo60
volatileTest1.addTo60();
System.out.println(Thread.currentThread().getName()+":ture后的"+volatileTest1.number);
},"web").start();
//上述的web线程已经将数据变成60;
//测试main线程是否感知到;
while (volatileTest1.number==0){
//就一直循环。什么都不会打印出来
}
System.out.println(Thread.currentThread().getName() +":"+volatileTest1.number);
//表示main线程也知晓了number的变化---满足了volatile的可见性的需求
/*
*
* web:come in0
web:ture后的60
main:60
*
* */
}
}
2.不保证原子性:
volatile支持可见性--;
原子性: 与mysql事务中的类似,不可分割,完整性,
也即是某个线程在工作时,中间不可以加塞和分割,要么整体同时成功,要么失败;
原子性:--丢数据的形式;基本是没可能;
a++不能保证原子性; volatile不能保证原子性;
丢失数据的原因:
1. 细说a++的运行过程:
分为三步;
①读取,从主物理内存中的a----》拷贝到本地的线程的工作内存;
②加一:
③写回主内存同步数据
不保证原子性就是--可能会在线程操作的过程中会有数据抢占;
随时可能会被打断;
不保证原子性--就会出现写覆盖的情况;--
2. 怎么解决volatile的不保证原子性情况:
①加synchronized的同步机制锁(太重啦)
注意:atomicInteger的底层就是Cas的;
②juc中的atomic包中的一个atomicInteger的类
a++;
方法是一个
atomicInteger.getAndIncrement(); //每次加1-保证原子性的加1
//底层就是CAS的; atomicInteger.getAndIncrement()
//解决的是volatile不保证原子性的AtomicInteger
//AtomicInteger是 java.util.concurrent.atomic原子包写的类
AtomicInteger atomicInteger=new AtomicInteger();
public void addMyatomic(){
atomicInteger.getAndIncrement(); //每次加1-保证原子性的加1
/**
* Atomically increments by one the current value.
*原子性增加1
* @return the previous value
*/
/*public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}*/
}`
`package com.atguigu;
import com.sun.org.apache.xpath.internal.operations.Variable;
import javax.lang.model.element.VariableElement; import java.util.concurrent.atomic.AtomicInteger;
class VolatileTest2{ //资源类
volatile int a; //全局变量的默认为0
public void addPlusPlus(){
this.a++;
}
//解决的是volatile不保证原子性的AtomicInteger
//AtomicInteger是 java.util.concurrent.atomic原子包写的类
AtomicInteger atomicInteger=new AtomicInteger();
public void addMyatomic(){
atomicInteger.getAndIncrement(); //每次加1-保证原子性的加1
/**
* Atomically increments by one the current value.
*原子性增加1
* @return the previous value
*/
/*public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}*/
}
}
public class VolatileNoAtomic {
//volatile 不保证原子性的小李子
public static void main(String[] args) {
//1.创建资源类的对象
VolatileTest2 volatileTest2=new VolatileTest2();
//2.创建线程-开始循环-
for(int i=1;i<=30;i++) {
new Thread(()->{
for (int j = 0; j <100 ; j++) {
volatileTest2.addPlusPlus();
volatileTest2.addMyatomic();
}
},String.valueOf(i)).start();
}
//3.main线程是在a++之中有感知的,
System.out.println(Thread.currentThread().getName()+"addPluePlus"+":"+volatileTest2.a);
//得出加过后的最后的值atomiceInteger
System.out.println(Thread.currentThread().getName()+"atomicInteger"+":"+volatileTest2.atomicInteger);
/* mainaddPluePlus:2797
mainatomicInteger:3000
*/
//底层就是CAS的; atomicInteger.getAndIncrement()
}
} `