zoukankan      html  css  js  c++  java
  • 简述JMM

    一、很多初学者分不清JMM和JVM的内存模型,本篇只是简要的谈一谈什么是JMM,并不深入探讨。

      示意图A:

      

      在多线程操纵共享资源时,并不是对资源本身进行的操作,而是将共享资源的副本复制了一份到自己的私有空间中,等使用完了再写回去覆盖原资源,我可能在瞎说,你先别信,举个例子来验证一下:

      

    
    
    class Number{
    int count = 0;
    public void add(){
    this.count = 1;
    }
    }
    public class Demo2 {
    public static void main(String[] args) {
    Number number = new Number();

    new Thread(() -> {
    System.out.println(Thread.currentThread().getName()+"***come in");
    try{
    TimeUnit.SECONDS.sleep(5);
    }catch (Exception e){
    e.printStackTrace();
    }
    number.add();
    System.out.println(Thread.currentThread().getName()+" newCount: " + number.count);
    },"A").start();
    new Thread(() -> {
    System.out.println(Thread.currentThread().getName()+"***come in");
    while (number.count == 0){
    try{
    Thread.sleep(1000);
    System.out.println("wait...");
                //重新从主内存获取资源(number.count)
                //System.out.println(Thread.currentThread().getName() + " newCount: " + number.count);
                    }catch (Exception e){
    e.printStackTrace();
    }
    }
    System.out.println(Thread.currentThread().getName()+" newCount: " + number.count);
    },"B").start();
    }
    }
     

      输出结果很奇怪:A线程将count设置为1结束后,B线程却不停的每秒钟输出一个wait... , 为什么A线程将count设置为1,B没有跳出while循环呢?因为B并不知道A已经将count值改变了,A线程用的count是之前从主内存拷贝而来的,而不是直接使用的主内存中的number的count。A也是先将主内存中的内容复制到自己的私有工作内存空间中,但是进行操作后便将数据写会到主内存中,但这些操作B线程并不知道,只有B线程重新获取资源才会知道主内存资源发生了改变,因此如何让B线程“知道”A线程已经将数据改变,是由现实需求的。

    二、volatile关键字

    class Number{
        volatile int count = 0;
        public void add(){
            this.count = 1;
        }
    }

      给count变量加一个volatile关键字修饰,A线程修改count值后,即使B线程没有主动从主内存中获取最新资源,也会有一种“通知机制”告诉他你的值不是最新的了,你需要从主内存中获取最新的资源,两个线程是这样,多个线程也是这样。我们称这样的通知机制为“可见性”。

      可见性:1、修改volatile变量时会强制将修改后的值刷新到主内存中

          2、修改volatile变量后会导致其他线程工作内存中的对应变量值失效。因此,再读取该变量值的时候就需要重新从主内存中读取新值。

      

      上面的add()方法里面操作时原子性操作,如果如果把add()方法改成:

    class Number{
        volatile int count = 0;
        public void add(){
            this.count = count++;//count++不是原子性操作
        }
    }

      输出结果和没有加volatile是一样的,还是不停的输出wait... ,也就是说volatile适用于原子性操作,那如果对变量的操作不是原子性操作,怎么才能实现这种通信呢?使用锁!

    class Number{
        volatile int count = 0;
        public synchronized void add(){
                this.count = count++;
        }
    }
    class Number{
        Lock lock = new ReentrantLock();
        volatile int count = 0;
        public synchronized void add(){
            lock.lock();
            try{
                this.count = count++;   
            }finally {
                lock.unlock();   
            }
        }
    }

      通过加锁,也可以实现 “原子性”。我们来分析一下为什么为什么count++不是原子性操作,执行count++,一共分为三步,将内存中的count读到CPU寄存器,然后执行自增操作,最后写回内存。

  • 相关阅读:
    python拆包与装包-*args,**kwargs
    mybatis学习4-CRUD操作
    mybatis学习3-入门案例,注解方式
    mybatis学习1-前置,复习Jdbc
    spring框架学习-aop
    spring学习1-第一个spring项目
    spring概述
    idea的一些个人设置
    maven的一些个人设置
    VBA文件对话框的应用(VBA打开文件、VBA选择文件、VBA选择文件夹,VBA遍历文件夹)
  • 原文地址:https://www.cnblogs.com/superlsj/p/11678254.html
Copyright © 2011-2022 走看看