java多线程-线程之间的可见性

本文探讨了Java多线程中的可见性问题,包括共享变量不可见的原因、synchronized和volatile如何确保可见性,以及happens-before原则保证有序性的八种情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java多线程-可见性

定义:一个线程对主内存的修改可以及时的被其他线程观察到
共享变量在线程间不可见的原因:

① 线程交叉执行
② 线程交叉执行结合指令重排序
③ 共享变量没有在更新后的值没有在工作内存与主存之间及时更新

synchronized的两条规定

① 线程释放锁前,必须把共享变量的最新值刷新到主内存当中
② 线程获取锁时,将当前线程的本地内存置为无效,从而使用共享变 量时需要从主内存中重新读取最新的值

volatile通过内存屏障和禁止重排序以及禁止中断优化来实现(从CPU的角度去看)

① 对volatile类型变量进行写操作时,会在写操作后面加入一条store 屏障指令,将本地内存中的共享变量值刷新到主内存当中;
② 读取volatile类型变量时,会在读操作前加入一条load屏障指令,从 主内存中读取共享变量;
③ volatile变量在线程每次访问的时候都强迫线程从主内从读取变 量,而当该变量发生变化的时候又会强迫线程将最新的值刷新到主 内存中,这两个操作保证了volatile线程之间的可见性;
④ volatile只是保证了共享变量的可见性,并没有保证volatile修 饰的变量的所有操作都是原子操作。对于被volatile修饰的变量 用于get方法和set方法都是线程安全的;此时相当于在get和set 方法上面添加了synchronized关键字。但是对于非原子操作的就 不是线程安全的方法;
⑤ volatile适合用于作为检查某个状态标记量以判断是否退出循环 和双重检测机制(安全单例模式)

有序性-happens-before原则
  • 1、程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于写在后面的操作(虽然虚拟机可能进行了重排序,但是程序 执行的顺序看起来是按照在代码书写的样式执行的。只会对数据不存在依赖性的指令进行重排序);这条规则只能保障单线程中保持正 确性,而无法在多线程中保持正确性。
  • 2、锁定规则:一个unlock操作先行发生于后面对同一个资源lock的操作(对一段代码或一个变量,只有锁定了资源的锁先执行了unlock操 作,下一个线程才有可能执行lock操作。这里需要注意,当一个锁再一次进入同一个锁的时,这时候是否先执行unlock还是怎样??不会,这是可重入锁,不会进行释放,而是计数量会+1)
  • 3、volatile变量规则:对一个变量的写操作先行发生于后面这个变量 的读操作。
  • 4、传递规则:如果操作A先发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
  • 5、线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作
  • 6、线程中断规则:对线程interrupt()方法的调用先行发生于被中断的代码检测到中断事件的发生。(只有执行了中断方法以后才能检测中断时间的发生)
  • 7、线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回手段检测到线程已经终止执行。
  • 8、对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值