zoukankan      html  css  js  c++  java
  • 关于JAVA中的JMM内存模型

    关于JAVA中的JMM内存模型

    在Java中当多个线程操作同一个资源,由于某些原因当一个线程启动并获取资源后,若第二个线程队同一个资源进行了改动,在改动之前的线程并不会马上获取主存中的资源(CPU嗅探),这可能会造成阻塞.

    JMM内存模型如下图:

    为了解决这一问题,我们需要应用volatile关键字,volatile保证了资源的可见性、但不保证资源的原子性.

    import java.util.concurrent.TimeUnit;
    
    public class JMMDemo {
        // 不加 volatile 程序就会死循环!
        // 加 volatile 可以保证可见性
        private volatile static int num = 0;
    
        public static void main(String[] args) { // main
    
            new Thread(()->{ // 线程 1 对主内存的变化不知道的
                while (num==0){
    
                }
            }).start();
    
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            num = 1;
            System.out.println(num);
    
        }
    }
    

    但是volatile关键字并不保证原子性,怎样保证资源的原子性呢?当然可以使用lock锁或者synchronized关键字,但这显然会降低程序的运行效率,在不考虑使用锁和同步代码块的情况下,我们可以使用JUC中提供的AtomicInteger类,详细代码如下:

    import java.util.concurrent.atomic.AtomicInteger;
    
    // volatile 不保证原子性
    public class VDemo02 {
    
        // volatile 不保证原子性
        // 原子类的 Integer
        private volatile static AtomicInteger num = new AtomicInteger();
    
        public static void add(){
            // num++; // 不是一个原子性操作
            num.getAndIncrement(); // AtomicInteger + 1 方法, CAS
        }
    
        public static void main(String[] args) {
    
            //理论上num结果应该为 2 万
            for (int i = 1; i <= 20; i++) {
                new Thread(()->{
                    for (int j = 0; j < 1000 ; j++) {
                        add();
                    }
                }).start();
            }
    
            while (Thread.activeCount()>2){ // main  gc
                Thread.yield();
            }
    
            System.out.println(Thread.currentThread().getName() + " " + num);
    
    
        }
    }
    

    在代码的第11行中注释写到num++;其实并不是一个原子性操作,如果使用java的反编译命令查看字节码文件可

    看出num++;的底层确实不是原子性的操作

    至此,我们已经可以解决在多线程并行的情况下,主存与线程工作内存的一致性和可见性了,正如JMM内存模型要求的那样.

    Keep Clam and Carry Keen.
  • 相关阅读:
    Android 自定义View (二) 进阶
    设计模式 装饰者模式 带你重回传奇世界
    Android 自定义View (一)
    C++ 习题 输出日期时间--友元类
    设计模式 观察者模式 以微信公众服务为例
    Binomial Coeffcients 历届山东省省赛题
    做一只美腻的程序媛
    java编程中容易犯2的细节汇总
    Arrays.asList()
    SQL Server用表组织数据
  • 原文地址:https://www.cnblogs.com/MrKeen/p/JMM.html
Copyright © 2011-2022 走看看