JMM 三大特性 : 可见性,不保证原子性,禁止指令重排

我们大家都知道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,接下来各位提意见.我再补充,懂了的点赞.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值