我们大家都知道JVM是java虚拟机,那JMM是什么呢?是java内存模型.
JMM全名为Java Memory Model,本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量,(包括实例字段,静态字段,和构成数组对象的元素)的访问方式.
接下来说它的三大特性:
1.可见性.可见性就是线程对变量的操作 ,必须在工作内存中进行,首先要将变量从内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存.
代码:
class MyData // mydata.java ---> muydata.class ===> jvm字节码
{
volatile int number = 0;
public void addT060()
{
this.number = 60;
}
public void addPlusPlus(){
number ++;
}
AtomicInteger atomicInteger = new AtomicInteger();
public void addAtomic(){
atomicInteger.getAndDecrement();
}
}
private static void seeOkByVolatile() {
MyData myData = new MyData();//资源类
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"\t come in");
//暂停一会线程
try {
TimeUnit.SECONDS.sleep(3);}catch (InterruptedException e){e.printStackTrace();}
myData.addT060();
System.out.println(Thread.currentThread().getName() + "\t updated number value:" + myData.number);
},"AAA").start();
// 第2个线程就是我们的main线程
while (myData.number == 0 ){
//main线程就一直在这里等待循环,直到number值不再等于零
}
System.out.println(Thread.currentThread().getName() + "\t mission is over" +myData.number);
}
当不可见与可见时,打印出来的数据是不一样的,大家可以根据自身的时间去测试
二: 不保证原子性,
什么是原子性呢?
原子性是同时成功,或者同时失败.记住,在这里是不保证原子性
接下来看一下代码:
class MyData // mydata.java ---> muydata.class ===> jvm字节码
{
volatile int number = 0;
public void addT060()
{
this.number = 60;
}
public void addPlusPlus(){
number ++;
}
AtomicInteger atomicInteger = new AtomicInteger();
public void addAtomic(){
atomicInteger.getAndDecrement();
}
}
/**
* 1.验证volatile 的可见性
* 1.1 假如int number = 0 ,number变量之前根本没有volatile关键字修饰,没有可见性
*1.2添加volatile , 解决可见性问题
*
* 2.验证volatile不保证原子性,
* 2.1 原子性,要么同时成功,要么同时失败
*
*/
public class volatileDemo {
public static void main(String[] args) {
MyData myData = new MyData();
for (int i = 1; i<=10;i++){
new Thread(()->{
for (int j = 1 ;j<=1000;j++){
myData.addPlusPlus();
myData.addAtomic();
}
},String.valueOf(i)).start();
}
// 需要等待上面20个线程都计算完成,再用main线程取得最终结果
// 暂停一会
while (Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "finallly number value: "+ myData.number);
System.out.println(Thread.currentThread().getName() + "int AtomicInteger finallly number value: "+ myData.atomicInteger);
}
}
当不保证原子性时,打印出来的是1000一下的数字,并且会不停的变.这与我们想要的数据并不一致.那怎么解决呢?
1.加 sync,这个大家都明白.不再多说.
2.使用我们的juc下的Atomic
那为什么Atiomic可以解决呢?
https://www.cnblogs.com/Mainz/p/3556430.html
这篇文章可以解决我们的问题.
当然,因为时间原因,如果你能顺着了解一下caas和自旋锁就更好了.!
三,禁止指令重排
那什么是指令重排呢?
用最简单的语句来解读这两幅图 就是多线程可运行的线程先后顺序可变,但也有规定,比如说:
1. a = 1
2. b = 2
3. c = a + b
这就不能先执行3.为什么呢.因为c是a与b相加的变量.因此.就不允许指令重排.
OK,接下来各位提意见.我再补充,懂了的点赞.