常见的锁策略
常见的锁策略
一:什么是锁策略???
策略就是方法,如何做.
锁策略就是在加锁/解锁/遇到锁冲突的时候,都会怎么做.
二:常见的锁策略
2.1:悲观锁 VS 乐观锁
加锁的时候,JVM能够预测当前锁冲突的概率是大还是小.
预测当前锁冲突概率比较大,后续要做的工作往往就会更多,加锁的开销(时间,系统资源)就更大=>悲观锁
预测当前锁冲突概率不大,后续要做的工作往往就更少,加锁的开销(时间,系统资源)就更小=>乐观锁
悲观锁往往是要通过内核来完成一些操作的,要做的工作就多.
乐观锁往往是纯用户态的一些操作,要做的工作就更少.
2.1.1:java中使用的synchronized是哪种锁??
synchronized支持自适应,能够自动统计出当前的锁冲突的次数,进行判定当前是锁冲突概率高还是概率低.
当冲突概率低的时候,就是按照乐观锁的方式来执行的(加锁开销小,速度更快)
当冲突概率高的时候,就会升级成悲观锁的方式来执行(做的工作更多)
2.2:重量级锁 VS 轻量级锁
一般来说,悲观锁,往往就是重量级锁,乐观锁就是轻量级锁.
实际交流过程中,这两组概念,可能会混着用,但深究的话,这两组概念的出发点是不同的:加锁的过程中做的事情多,就是重量级锁,加锁的过程中,做的事情少,就是轻量级锁;而乐观锁,悲观锁,是先预测一下,锁冲突的概率是低还是高,
2.3:自选锁 VS 挂起等待锁
自选锁,是轻量级锁的一种典型实现方式.
自旋锁:一旦锁被释放,就能第一时间拿到锁,拿锁的速度更快,消耗的CPU更多
挂起等待锁:是重量级锁的一种典型实现方式.
借助系统中的线程调度机制,当尝试加锁,并且锁被占用了,出现了锁冲突,就会让这个尝试加锁的线程,被挂起(阻塞状态),此时这个线程就不参与调度了,直到这个锁被释放,然后系统才能唤醒这个线程,去尝试重新获得锁.
挂起等待锁,消耗的时间更长,一旦一个线程被阻塞了,线程多了,啥时候被唤醒,这个过程是不可控的,可能会经历很长很长的时间.
挂起等待锁:拿到锁的速度更慢,节省CPU.
synchronized轻量级锁部分,基于自旋锁实现(基于CAS机制来实现的);重量级锁部分,是基于挂起等待锁实现(调用系统API,通过内核).
举个栗子:
你向女神表白,然后女神表示,我有男朋友了(女神已经被加锁了)
你的处理方式就有两种了:
(1)自旋锁:仍然每天都会给女神问候早安,午安,晚安,吃了吗?睡了吗?..
一旦女神分手了,此时第一时间就能感知到,于是就更有机会上位.
(2)挂起等待锁:把女神拉黑,从此不再联系,自己每天好好学习,好好健身,做更好 的自己,后来某一天,通过别人,听说,女神分手了,再把女神加回来,再尝试获取锁.
消耗的时间是更多的,女神分手,第几次分手之后,能够加锁成功,是不确定的
2.4:可重入锁 VS 不可重入锁
可重入锁:一个线程,针对一把锁,连续加锁两次及以上,不会死锁
不可重入锁:一个线程,针对一把锁,连续加锁两次及以上,会死锁
synchronized是可重入锁,是因为锁对象里,会记录当前是哪个线程持有了这个锁,但针对这个锁对象进行加锁操作的时候,就会先判定一下,当前尝试加锁的线程,是否是持有锁对象的线程,如果是,直接进行加锁操作,如果不是,那就阻塞等待.同时也要引入计数器,确保成功解锁
2.5:公平锁 VS 非公平锁
当然,公平是基于不同的规则下的.
比如:每个线程获取到锁对象的机会是否均等,均等,就是公平的,不均等,就是不公平的.
此时的公平,是按照先来后到规则制定的.
公平锁:当有多个线程尝试对同一个锁对象进行加锁操作的时候,就会严格按照先来后到的顺序来获得锁对象,哪个线程阻塞等待的时间长,(就是最先阻塞等待的,),哪个线程就先拿到锁对象.
非公平锁:若干个线程,各凭本事,随机的获取到锁,和线程等待时间就无关了.
synchronized属于非公平锁,多个线程,尝试获取锁对象,和线程的等待时间无关了,此时是按照概率均等的方式来进行获取的(系统本身线程调度的顺序就是随机的,如果需要实现公平锁,就需要引入额外的队列,按照加锁的顺序,把这些获取锁的线程入队列,再一个一个的取).
2.6: 互斥锁 VS 读写锁
synchronized 本身就是普通的互斥锁,只有加锁和解锁操作.
读写锁:是一个更特殊的锁:有加读锁,加写锁,解锁操作.
读写锁更具体点就是:
(1):读锁和读锁之间,不会产生互斥(提高了并发能力)(多个线程读同一个变量,不会有线程安全问题)
(2)写锁和写锁之间,会产生互斥.
(3)读锁和写锁之间,会产生互斥.
读写锁突出体现的是"读加锁和读加锁"之间是共享的(不会互斥的),有利于降低锁冲突的概率,提高并发能力.
Java标准库/操作系统API也提供了读写锁的实现.
日常的开发中,有很多场景,属于"读多,写少",大部分都是读操作,偶然有写操作,如果使用普通的互斥锁,此时,每次读操作,都会互斥,就会影响效率,如果使用多谢锁,就能够有效的降低锁冲突的概率,提高效率.
原文地址:https://blog.csdn.net/2302_77978695/article/details/137693465
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!