| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> Java并发——公平锁,非公平锁,悲观锁,乐观锁,死锁 -> 正文阅读 |
|
[Java知识库]Java并发——公平锁,非公平锁,悲观锁,乐观锁,死锁 |
个人博客:haichenyi.com。感谢关注 前言??这几个锁都可以从前面一篇线程同步器AQS里面找到影子,我先把前面一篇的加锁流程图拿过来用一用。 ??上面这个流程图是上一篇最开始讲的时候的一张流程图,后面写的时候,后面的流程图都没有画。这一片我们来画一下后面的流程图。 公平锁,非公平锁??前面一篇讲的时候,我说过了,我们当时做的是一个公平锁。这个公平锁和非公平锁的主要区别就是在这个队列。 ??我们前文讲过了,线程1拿到了锁,线程2,3,4就全部放进队列中等待,那么,流程图如下: ??如上图,我们理想状态是:线程1释放锁的时候,队列中的第一个元素,也就是线程2拿到锁,然后,开始执行。 ??但是,往往不如意,谁规定的一共就只有4个线程呢?如果,我们正当1释放锁的同时,又有一个线程5进来了,我们要怎么操作呢?流程图如下: ??公平锁和非公平锁的区别就在这里:
??所以,公平锁就是释放锁之后,谁等待得时间长,谁先执行。非公平锁则是,释放锁之后,谁先获取到锁,谁先执行。可能后进的执行,也可能先进的先执行。 ??ReentrantLock,初始化的时候传true就是公平锁,传false就是非公平锁,默认是非公平锁。下面就是ReentrantLock的构造方法。
悲观锁锁,乐观锁??悲观锁:操作之前加锁,操作完成之后解锁。我们前文讲的buy方法就是悲观锁,进入方法就加锁,方法执行完就解锁。还有我们常用的synchronized关键字,就是悲观锁的典型代表。 ??乐观锁:乐观锁是一种思想,比方说,我们前文提到的CAS机制,就是乐观锁的一种实现。当我们操作一个变量做加减操作的时候,我们多个线程可以同时做这个操作,但是到具体更新这个值的时候,去判断。典型代表就是Atomic原子类。这个原子类的实现也是CAS机制。 ??性能问题:多个线程同时执行,悲观锁,就只有一个线程操作,其他线程挂起等待,释放锁之后,再切换回来。乐观锁,所有的线程都一起执行,最后执行冲突检测和数据更新操作。没有挂起等待,上下文的切换,所以,乐观锁的性能肯定比悲观锁好。但是,实际上真的是这样吗?答案是否定的。乐观锁的性能不一定比悲观锁好。 ??前面,我们说到乐观锁是在最后更新得时候,去判断。那么怎么判断呢?早期1.5版本之前的CAS操作是有3个参数内存位置(V)、原值(A)、新值(B)。我们在更新的时候,先判断A是否满足,满足就更新成B上一篇文章已经说过了。不满足,那就再循环一边重复判断。极端情况下,要是线程足够的多,并且一直不满足,那是不是一直循环判断(CAS自旋)?那就一直占用CPU。这样性能肯定不好。 ??synchronized在JDK1.5之前的确性能很差,但是在1.6的时候就已经做了优化了,从无锁状态,到偏向锁状态,再到轻量级锁状态,最后到重量级锁状态。这几个状态会随着竞争情况逐渐升级(锁不但可以升级还可以降级)。现在synchronized的性能跟ReentrantLock差不多。 ??所以,悲观锁的性能不一定比乐观锁差,乐观锁的性能不一定比悲观锁好。根据实际情况去选择悲观锁和乐观锁。那到底怎么选择呢? ??之前在网上看到过这么一组数据,启用多个线程进行计数相加到一亿,首先是synchronized方式 ??当线程数为8时,性能明显提升,但是8到32个线程来说,每个线程的平均时间基本差不多,基本没有提升,到了64个线程的时候,性能又有一点提升。 如果换成CAS实现多线程累加数为一亿,时间又会怎么样呢? ??在线程数相对较少的时候,CAS实现比较快,性能优于synchronized,当线程数多于8后,CAS实现明显开始下降,反而时间消耗高于synchronized; ??总结:synchronized是java提供的又简单方便,性能优化又非常好的功能,建议大家常用;CAS的话,线程数大于一定数量的话,多个线程在循环调用CAS接口,虽然不会让其他线程阻塞,但是这个时候竞争激烈,会导致CPU到达100%,同时比较耗时间,所以性能就不如synchronized了。 死锁概念??死锁是指:多个进程在运行过程中因争夺某一种资源,而造成的僵持状态,若无外力作用,他们都将无法向前推进。 举个栗子: 小明在看电视,小红在玩手机,小明对小红说:你把手机给我玩,我把点视给你看;小红却说:你把点视给我看,我再把手机给你玩。 分析:
??所以,小明和小红都在等待对方释放锁,自己拿到想要的资源之后,释放自己资源的锁。这里谁都拿不到锁,就无线的等待下去。这就是死锁。 产生条件
解决办法??如果产生死锁只能重启。所以,我们在开发过程中要尽量避免死锁,比方说:著名的银行家算法。只要上面四种中的任意一种不满足,就不可能造成死锁:比方说占有等待,我们可以用共享锁的方式AQS里面每个加锁的方法都有一个try开头的方法。可以看一下acquire和tryAcquire的区别。这就破坏了第二个条件,等待。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年3日历 | -2025/3/4 3:12:51- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |