多线程进阶之各种锁的策略

多线程进阶:
多线程初阶,主要讲了一些多线程的基础原理和一些编程方法(并发编程)。
*多线程进阶(面向面试学习)
一、各种锁的策略。
二、CAS机制【比较实用】
三、java.util.concurrent.的一些实用的类。
四、sychronized实现原理和锁优化策略。
五、ConcurrentHashMap【面试考点】。

一、各种锁的策略。
1.乐观锁 vs 悲观锁

广义概念:锁的两种不同的实现思路。
乐观的人会认为:世界大概率不会出问题。
悲观的人会认为:世界大概率会出问题。
例:当两个人在野外被困时,粮食只剩下两个馒头了。悲观的人会说,咱俩就剩下俩馒头啦~~,乐观的人会说,还好咋俩还有两馒头。你细品。
乐观锁:认为多个线程同时竞争所得概率较低 ,会花更少的成本来解决锁竞争问题。(没那么安全,但是代价小)
悲观锁:认为多个线程同时竞争锁的概率很高,愿意花更多的成本来解决竞争问题。(更安全,但是代价大)
这两种锁其实没有高低好坏之分,只有哪一种锁更适合哪一种场景之说。这个需要锁的实现者根据实际情况来决定使用哪种锁的策略。
2.读写锁【非常有用】
加锁时分成两种情况:
a)加读锁,线程只能去读取数据,不能够修改数据。
b)加写锁,线程可以读取数据,也能修改数据。
在实际开发情况中:很多场景都是“一写多读”=》写的次数非常少,而读的次数非常多。正确使用读写锁,效率会比较高。
注意:读锁和读锁之间,不会产生互斥的。(不会产生锁竞争)=》只有当多个线程尝试修改同一变量,才会导致不安全。
读锁和写锁之间,写锁和写锁之间,才会发生互斥(发生锁竞争)
举个例子:学校教务系统上的作业,每次布置作业的时候,都需要查看(作业是提前准备好的,可能每个学年或者每个学期才会进行更新,但是每天都会读)。
或者说一个贴吧或者论坛看帖的频率远高于回帖或者发帖的频率。

只有触发写操作才会真的进行锁竞争。写操作比较少,读操作很多,大部分情况下是没有锁竞争的。于是操作效率就会很高。
当教务系统的作业正在被一个老师修改时,这个老师就会加上写锁。同学们就无法读取数据了。直到这边写完,才会允许其他同学继续来读内容。
此时如果另一个老师也想来修改同一个作业,就会和上一个老师触发互斥。
如果无人修改作业内容,此时无论有多少个同学同时来读取作业内容,都不会引起线程安全问题。此时读者和读者之间没必要加锁。
3.重量级锁 vs 轻量级锁
重量/轻量指的是 锁竞争 开销大还是不大。
锁之所以能保持原子性,得有力量的源泉~~
应用程序 =》 JVM =》 OS =》 硬件设备 =》 物理上的知识了(有兴趣的可以自己查查,反正我不会,哈哈哈)
重量级锁:实现的过程中就大量依赖了操作系统提供的功能。(mutex),成本就比较高。(大量的操作都是在内核态完成的)
轻量级锁:实现过程中,只有迫不得已的地方才依赖操作系统的功能,成本比较低。(在内核完成的工作比较少)
代码在操作系统内核中运行。操作系统内核来完成的软硬件管理的任务。应用程序也是要跑在内核之上。
比如说我在银行,我把我的资料交给银行柜员之后,柜员就会敲电脑,这个过程就相当于代码在内核运行的过程。
有的工作,在内核中能做,在用户态也能做。
重量级锁,就是把这些工作全部交给了内核了。
轻量级锁,就是把自己能做的都尽量做了,实在是做不了的再交给内核。
4.自旋锁 vs 挂起等待锁
这是一种轻量级锁(很多工作在用户态自己就完成了)
当多个线程去竞争一把锁的时候,如果发现锁已经被别人占用了:
(1)、挂起等待锁。线程放弃CPU上的执行权限,该线程的 PCB 就会被内核放到对应的等待队列中。直到锁被释放之后,才有机会被唤醒。
(2)、自旋锁。线程先别放弃 CPU 而是快速反复的去查询当前所的占用状态,效率会高于挂起等待锁。
CPU 是稀缺资源,线程能够上CPU 执行,是一个很来之不易的事情。
挂起等待锁,发现锁被占用就立刻放弃 CPU ,这样就非常可惜。
自旋锁,发现锁被占用,不会立刻释放,而是会快速仿佛的多次查询锁的状态。万一要是几个时钟周期后锁就被释放了的话,此时咋们这个线程就能快速的获取到锁资源。
举个例子:当你去包子店买包子,发现包子没了~~,此时你有两个选择:
(1)扭头就走,回家~过一会儿再来看。(挂起等待锁)
(2)在这个小摊周围转悠转悠。等一等。(好比自旋锁)
自旋锁带来的代价就是要付出更多的 CPU 资源。(这些资源没有在做事情,而是在空转)
各有各的好处,就看锁的实现者如何抉择了。
5.公平锁 vs 非公平锁
有若干个线程都想竞争锁。来了一个线程A,线程 A 来的时候,正好锁被释放了。
公平锁:但是线程 A 排到原来的线程后面,等到前面的线程都把锁使用完之后,线程 A 再获取锁。
非公平锁:线程 A 直接把锁抢走了~(正如字面意思一样,非公平锁是直接插队抢锁的)
公平锁的好处,能够让每个线程都能够“雨露均沾”,要想实现公平锁至少需要维护一个队列来排队,需要付出更多的代价。
非公平锁,虽然每个线程获取锁的概率不均衡,但是实现更加简单,代价更小。
上面第4点的自旋锁,更容易触发“非公平锁”的场景。
6.可重入锁 vs 不可重入锁
如果一个线程针对同一把锁,连续加锁两次,不会造成
“死锁”
,就是可重入锁。如果造成了死锁,就是不可重入锁。
锁如果不加特殊处理,就是不可重入锁,如果记录锁是谁加的,此时就可以实现可重入锁。
判断正在尝试加锁的线程和正在持有锁的线程是否同一个线程。如果是,就可以放行,这就实现了可重入锁。
死锁:
一旦出现死锁,相关的线程就无法被唤醒继续执行了。
死锁的三种典型的场景:
(1)一个线程,一把锁。(上面锁的这种情况,连续加锁两次,且是不可重入锁)
(2)两个线程 1,2,两把锁 A,B,线程1获取锁A(成功),线程2获取锁B(成功),接下来线程 1 尝试获取锁 B 的同一时刻线程 2 尝试获取锁 A。就会造死锁,
针对(2)举个例子:你和你的小伙伴一起玩,你玩手机,他玩电脑,过了一会儿,你们同时想要换着玩,但是他要求你先把手机先给他,他再给你电脑,你不甘示弱,要求他先把电脑给你,你再给他手机,这个时候,谁也不肯让步,就僵住了。形成死锁了。
(3)N 个线程 N 把锁。更容易出现死锁了。


当前已经知道了这些锁策略。
一个真是锁的实现,往往会同时具备多种策略。
sychronized(JDK 1.8中)(我使用的是jdk1.8,这里只说我知道的一些东西)
1.开始时乐观锁,后面可能转换成悲观锁(自动转换的)
2.开始是轻量级锁,后面可能会膨胀成重量级锁。
3.轻量级锁基于自旋来实现的,重量级锁就是挂起等待(内核完成挂起等待)
4.不公平锁
5.可重入锁
6.不是读写锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值