当前位置: 首页 > news >正文

总结多线程的各种锁

1、公平锁和非公平锁

        公平锁是严格按照线程请求的顺序来分配锁,每一个线程都能获取到锁,避免线程饥饿现象;相反,非公平锁表示线程竞争锁时可以插队来抢占资源。

        非公平锁在大多数情况下效率优于公平锁,因为公平锁涉及到线程状态的切换,这是一笔很大的开销;

        举例:当我们使用非公平锁时,如果线程A释放锁之后,本来应该唤醒队列中的线程B,此时却被没有进入到阻塞队列的线程C截胡了,线程C竞争到锁之后就直接执行业务逻辑,就不需要再进入到阻塞队列了,这样就省去了后续再唤醒线程C而带来的性能开销,当然,这对于原本需要唤醒的线程B是不公平的,但是却提升了锁竞争的性能。

        synchronized和ReentrantLock默认都是非公平的,ReentrantLock可以设置为公平锁,synchronized不能。

2、乐观锁和悲观锁

        乐观锁表示线程在更新数据时,认为不会有其它线程对数据进行修改,因此不需要加锁,但是在更新时会判断此期间有没有被别的线程修改过数据。具体实现:JUC包下的原子类的实现,就是使用乐观锁+CAS实现的。

        悲观锁在更新数据时,认为其它线程会更新数据,因此会加锁,别的线程想要修改数据,就必须获取锁,获取不到锁就被阻塞。具体实现:synchronized和ReentrantLock这种独占锁都是悲观锁的具体实现。

3、死锁

        两个线程互相获取对方已经拥有的资源而形成的对峙局面,成为死锁。在没有外部条件的干涉下,程序无法向下执行,一直阻塞。

        破局:得不到就放弃。设置获取锁的次数,超过该次数还没拿到锁,就放弃当前已经有用的资源,从而打破死锁。

4、活锁

        活锁出现在两个线程互相改变对方的结束条件,最后谁也无法结束。就跟你去银行取钱,你的银行卡密码一直在变,永远别想取到钱。

5、可重入锁

        线程在抢占到一个互斥锁资源后,在释放锁之前,再去竞争同一把锁时,无需等待,只需要记录重入的次数。

        常见的可重入锁,synchronized和ReentrantLock。

        可重入锁主要为了避免死锁。线程获取到X锁,在释放之前再次获取X锁,那就是自己和自己竞争,如果不可重入,那就会出现死锁。

6、共享锁和独占锁

        共享锁是指锁可以被多个线程所持有,数据加上共享锁之后,其他线程也只能加共享锁。

        共享锁只能读取数据,不能修改数据。

        独占锁是一次只能有一个线程持有锁,加上独占锁之后,其他线程无法对数加锁。

        独占锁可以修改数据,也可以读取数据。

        具体实现:ReentrantReadWriteLock称为读写锁,里边有两把锁,一把读锁,一把写锁;读锁是共享锁,写锁是独占锁,两者不能同时存在。

        因为独占锁是一种过于严格的加规则,限制了并发。避免了写/写冲突,读/写冲突,但是也避免掉了读/读冲突。在大多数情况下都是读的场景,因此使用共享锁就可以提升性能。ReentrantReadWriteLock适用于读多写少的场景。

7、读写锁

        读写锁管理一组锁,一个是读锁,一个是写锁。

        读锁在没有写锁的情况下可以被多个线程共享;相反,写锁只能独占。

        写锁的优先级高于读锁。

8、互斥锁

         互斥锁是独占锁的一种具体实现,指某一个资源在同一时刻只能被一个线程访问,具有唯一性排他性。       

9、自旋锁

        线程没有获取到锁时,不是被直接挂起,而是执行一个忙循环,这个忙循环就是自旋。自选的目的是为了减小线程被挂起的概率,因为线程的挂起和唤醒也都是耗费资源的。

        一个特殊的情况是另一个线程占用所得时间很长,导致当前线程自旋时间也很长,之后线程还是会被挂起,那么这个自选操作就是读对系统资源的浪费,反而降低系统性能。

        具体实现:AtomicInteger原子类的getAndAddInt()方法,一个do-while循环,不断获取当前值Value,然后重试,循环退出条件为CAS返回true。

        优化:JDK1.6引入了自适应自旋,根据获取当前锁的上一个线程的自旋时间以及锁的拥有者的状态决定。如果虚拟机认为会成功,就多点自旋时间;如果认为会失败,那可能会将线程直接挂起,避免自选。

http://www.lryc.cn/news/277298.html

相关文章:

  • 树形结构的窗口小部件
  • 【现代密码学】笔记3.1-3.3 --规约证明、伪随机性《introduction to modern cryphtography》
  • Redis底层原理
  • 掌握亚马逊、Lazada、shopee、速卖通、eBay、wish测评自养号补单系统:解锁跨境电商新机遇
  • 15_多线程
  • 吉他打谱软件Guitar Pro8苹果Mac电脑简体中文特别版
  • go study oneday
  • Avatar虚拟数字人方案,元宇宙时代的企业新动力
  • 用golang 实现给图片添加文字水印
  • 苹果电脑Markdown文本编辑Typora mac功能介绍
  • 大型语言模型与知识图谱的完美结合:从LLMs到RAG,探索知识图谱构建的全新篇章
  • Vue 缓存Hook:提高接口性能,减少重复请求
  • 【Python机器学习】用于回归的决策树
  • numpy库的一些常用函数
  • 成员变量与局部变量的区别?
  • ES6---判断对象是否为{}
  • 高性能、可扩展、分布式对象存储系统MinIO的介绍、部署步骤以及代码示例
  • oracle重启数据库lsnrctl重启监听
  • 08、Kafka ------ 消息存储相关的配置-->消息过期时间设置、查看主题下的消息存活时间等配置
  • JAVA基础学习笔记-day15-File类与IO流
  • WPF ComboBox限制输入长度
  • windows配置网络IP地址的方法
  • windows配置电脑网络IP的方法
  • MySQL,原子性rename
  • FPGA之按键消抖
  • 国内知名的技术平台
  • C#操作注册表
  • Unity中BRP下的深度图
  • 物联网的感知层、网络层与应用层分享
  • kafka KRaft 集群搭建