zoukankan      html  css  js  c++  java
  • Java 内存模型

    1. 内存模型概念

    (1)内存模型(Java Memory Model)和内存结构(堆栈那些)不是一个层面的概念,JMM 定义了一套在多线程读写共享数据(成员变量,静态变量等,而不是局部变量这种线程私有的)时,对数据的可见性有序性、和原子性的规则和保障。

    (2)JMM规定了所有的变量都存储在主内存(虚拟机内存的一部分,但可以和操作系统的类比)中;

    每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取,赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量;

    不同的线程之间也无法直接访问对方的工作内存中的变量,线程间变量的值传递均需要通过主内存来完成。

    (3)如果非要把主内存工作内存,和内存结构的堆栈方法区对应,那么主内存应该对应堆中的对象的实例数据部分,而工作内存对应栈。

    2. 原子性

    要执行就执行完,不能执行一半

    违背原子性例子:两个线程对一个静态变量 i=0 执行 i++ 和 i--(每个对应四条JVM字节码指令),可能导致结果不是0

    解决:用synchronized加锁,加锁位置应尽量减少代码获取释放锁的次数

    synchronized( 对象 ) {
        要作为原子操作代码
    }

    3. 可见性

    指一个对象能看到或访问另一个对象的能力

    违背可见性的例子:t线程看不到主线程run变量的改变

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(run){
                // ....
            }
        });
        t.start();
        Thread.sleep(1000);
        run = false; // 线程t不会如预想的停下来
    }

    解决:volatile(易变关键字),它可以用来修饰成员变量和静态成员变量,线程操作 volatile 变量都是直接操作主存

    因此上面的run被修改后会存到主内存,t线程访问主内存内容会看到改变

    4. 有序性

    代码按顺序执行

    违背有序性的例子:由于即时编译器在运行时会有指令重排的优化,多线程情况下可能出现非预期结果

    解决:volatile 修饰的变量,可以禁用指令重排

    因此volatile可以保证可见性和有序性,不能保证原子性,但属于轻量级并发控制;而synchronized可以保证三者,但更重量级

    5. CAS

    CAS 即 Compare and Swap ,它的实现用的是乐观锁的思想

    // 需要不断尝试
    while(true) {
        int 旧值 = 共享变量 ; // 比如拿到了当前值 0
        int 结果 = 旧值 + 1; // 在旧值 0 的基础上增加 1 ,正确结果是 1
    
        if( compareAndSwap ( 旧值, 结果 )) {
        // 成功,退出循环
        }
    }
    • 获取共享变量时,为了保证该变量的可见性,需要使用 volatile 修饰
    • 结合 CAS 配合 volatile 可以实现无锁并发,适用于竞争不激烈、多核 CPU 的场景下
    • 因为没有使用 synchronized(悲观锁),所以线程不会陷入阻塞,这是效率提升的因素之一
    • 但如果竞争激烈,可以想到重试必然频繁发生,反而效率会受影响
    • CAS 底层依赖于一个 Unsafe 类来直接调用操作系统底层的 CAS 指令
    • 原子操作类例如:AtomicInteger、AtomicBoolean等,它们底层就是采用 CAS 技术 + volatile 来实现的
     


  • 相关阅读:
    Qt 利用XML文档,写一个程序集合 二
    Qt 利用XML文档,写一个程序集合 一
    Qt QpushButton 实现长按下功能
    Qt 将字符串转成16进制显示
    Qt-QML-Canvas-雷达扫描仪表简单
    Qt-QML-电子罗盘
    Qt-QML-Canvas写个小小的闹钟
    Qt-Qt5最新增加程序图标方式
    Qt-QMl-自定义自己想要的TabView
    设置position:fixed后元素脱离标准流的解决方法
  • 原文地址:https://www.cnblogs.com/Kinghao0319/p/14535057.html
Copyright © 2011-2022 走看看