3、共享模型之内存

该栏目讲叙多线程基础、共享模型的内存、管程、无锁、不可变设计和多线程并发工具


Java 内存模型

  • 概述:JMM 是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题
  • 特点
    • 原子性 - 保证指令不会受到线程上下文切换的影响
    • 可见性 - 保证指令不会受 cpu 缓存的影响
    • 有序性 - 保证指令不会受 cpu 指令并行优化的影响

可见性

1、举例

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

2、分析

  • 初始状态,T 线程刚开始从主内存读取了 run 的值到工作内存
  • 因为 T 线程要频繁从主内存中读取run的值,JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中,减少对主存中 run 的访问,提高效率
  • 1 秒之后,main 线程修改了 run 的值,并同步至主存,而 T 是从自己工作内存中的高速缓存中读取这个变量的值,结果永远是旧值

3、解决方法

  • :volatile 可以用来修饰成员变量和静态成员变量,它可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存

有序性

  • :JVM 会在不影响正确性的前提下,可以调整语句的执行顺序,添加 volatile 修饰的变量,可以禁用指令重排

happens-before 原则

  • 线程解锁前对变量的写,对于接下来加锁的其它线程对该变量的读可见
  • 线程对 volatile 变量的写,对接下来其它线程对该变量的读可见
  • 线程 start 前对变量的写,对该线程开始后对该变量的读可见
  • 线程结束前对变量的写,对其它线程得知它结束后的读可见
  • 线程 T1 打断 T2 前对变量的写,对于其他线程得知 T2 被打断后对变量的读可见
  • 对变量默认值的写,对其它线程对该变量的读可见
  • 具有传递性

volatile 原理

  • 可见性
    • 写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中
    • 读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中新数据
  • 有序性
    • 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
    • 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值