线程安全问题(中阶)

解决线程安全问题

要素 1 : 解决原子性问题(事务问题) !

要素 2 : 解决共享(对象)内存问题!

解决原子性 & 共享内存问题

我对解决原子性 & 共享内存的解决问题的看法

由于高级语言需要翻译成汇编语言/机器语言才可以在计算机上执行,且一条高级语言往往对应多条机器语言,
有因为CPU调度的最小单位是机器指令,也就是说机器指令的执行一定是原子的(事务的,不会被打断的!);
如果我们想要保证一段操作共享内存的指令序列不发生调度,就可以在一个指令的范围内对共享内存进行状态标记,
每段操作贡献内存的代码前都加上一个对标记的读操作(当然这个读操作也必须是原子的!),当标记为1时,表明内存已> 被占用,当标记为0时,表示资源没被占用,此时就可以占用这个共享内存即把标记置为1;
当然这是我猜的! 欢迎大佬们批评指正!!

我认为 原子性 & 共享内存 问题可以通过传递CPU指令的原子性进行解决;

Java 提供关键字 synchronized
Java 对锁进行抽象升级 Lock 对锁的规范

synchronized 的好处

synchronized 可以理解为一个智能的锁,它会根据情况来进行不同的加锁状态!
偏向锁 (轻量级锁) : 从第一个线程尝试加锁到第二个线程加锁期间,锁对象偏向于第一个线程! (Object 对象头偏向锁标识为 1 时,处于偏向锁状态,在这个状态下,第一次加锁成功的线程在下一次竞争锁时,会更有竞争力,JVM 比较懒,存过线程的标识就懒得去改变了) ;
自旋锁 (轻量级锁) : 当竞争锁的线程变多了,偏向锁就没办法应付了,所以退出偏向锁模式,进入自旋锁模式,当一个线程得到CPU时,有想要锁对象,但是得不到,如果放弃cpu去等待锁,等到锁后,再向上CPU是很难的(需要被调度的线程太多了,抢到CPU本就是一件不容易的事,哪有那么容易放弃的说法) 所以线程会选择继续持有CPU并定时获取锁。
(自旋锁的实现 依赖了计算机硬件的一条指令 CAS (compare and swap) ,众所周知CPU指令的执行一定是原子的);
互斥锁(mutex) 重量级锁: 当自旋锁迟迟抢不到锁还浪费CPU时,就锁就升级为互斥锁;

synchronized 原理结构图

在这里插入图片描述

等待集的解释 : 当一个锁被占有了,但任然有线程想要获得锁,而且属于是得不到就不走了,为了安置这些痴汉,锁妹妹给这些痴汉准备了等待的地方,等锁妹妹有空的时候会撩一波痴汉们!(这就叫养🐟)!

Lock 概念图

在这里插入图片描述

condition 等待集,就类似于虽然痴汉们都在等待锁妹妹,但是有人喜欢唱歌时的锁妹妹,有人喜欢跳舞时的锁妹妹!
锁妹妹懂得这些痴汉都喜欢什么,并把他们分类,当自己跳舞时,就给喜欢锁妹妹跳舞的痴汉机会,当锁妹妹唱歌时就给了喜欢锁妹妹唱歌时的状态的痴汉机会!

具体的函数啥的就不多介绍了,毕竟不难!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值