图解 Java 中的公平锁与非公平锁

关于 Java 中的锁,我这算是写了一个系列了!今天咱们进行写锁,Java 中的公平锁 VS 非公平锁。
web

网上关于 Java 中锁的内容有不少,因此我写的这些内容百度都不怎么喜欢,也很难搜索这些知识点到个人我的网站上。可是这些内容呢?我是想选择性的发表的个人我的微信公众号里!下面咱们开始本章的内容吧!微信

公平锁

公平锁是指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能得到锁。公平锁的优势是等待锁的线程不会饿死。缺点是总体吞吐效率相对非公平锁要低,等待队列中除第一个线程之外的全部线程都会阻塞,CPU 唤醒阻塞线程的开销比非公平锁大。flex

非公平锁

非公平锁是多个线程加锁时直接尝试获取锁,获取不到才会到等待队列的队尾等待。但若是此时锁恰好可用,那么这个线程能够无需阻塞直接获取到锁,因此非公平锁有可能出现后申请锁的线程先获取锁的场景。非公平锁的优势是能够减小唤起线程的开销,总体的吞吐效率高,由于线程有概率不阻塞直接得到锁,CPU 没必要唤醒全部线程。缺点是处于等待队列中的线程可能会饿死,或者等好久才会得到锁。网站

上面的解释可能优势抽象,下面咱们经过一张图来区别什么是公平锁?什么是非公平锁?spa

如上图所示,假设有一口水井,有管理员看守,管理员有一把锁,只有拿到锁的人才可以打水,打完水要把锁还给管理员。每一个过来打水的人都要管理员的容许并拿到锁以后才能去打水,若是前面有人正在打水,那么这个想要打水的人就必须排队。管理员会查看下一个要去打水的人是否是队伍里排最前面的人,若是是的话,才会给你锁让你去打水;若是你不是排第一的人,就必须去队尾排队,这就是公平锁。.net

可是对于非公平锁,管理员对打水的人没有要求。即便等待队伍里有排队等待的人,但若是在上一我的刚打完水把锁还给管理员并且管理员尚未容许等待队伍里下一我的去打水时,恰好来了一个插队的人,这个插队的人是能够直接从管理员那里拿到锁去打水,不须要排队,本来排队等待的人只能继续等待。以下图所示(仍是打水的例子):线程

完全的理解了 Java 中的公平锁与非公平锁后,咱们来看看 Java 中的 ReentrantLock。3d

阅读过 ReentrantLock 源码的都知道,它里面有一个内部类 Sync,Sync 继承 AQS(AbstractQueuedSynchronizer),添加锁和释放锁的大部分操做实际上都是在 Sync 中实现的。它有公平锁 FairSync 和非公平锁 NonfairSync 两个子类。ReentrantLock 默认使用非公平锁,也能够经过构造器来显示的指定使用公平锁。blog

下面咱们来看一下公平锁与非公平锁的加锁方法的源码:继承

经过上图中的源代码对比,咱们能够明显的看出公平锁与非公平锁的 lock() 方法惟一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors()。

再进入 hasQueuedPredecessors(),能够看到该方法主要作一件事情:主要是判断当前线程是否位于同步队列中的第一个。若是是则返回 true,不然返回 false。

综上,公平锁就是经过同步队列来实现多个线程按照申请锁的顺序来获取锁,从而实现公平的特性。非公平锁加锁时不考虑排队等待问题,直接尝试获取锁,因此存在后申请却先得到锁的状况。

Java 中使用公平锁的场景就是队列,FIFO。使用非公平锁的场景就是 ReentrantLock(默认非公平锁)!

最后,欢迎关注个人我的微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847,QQ3群:187424846。QQ群进群密码:xttblog,想加微信群的朋友,能够微信搜索:xmtxtt,备注:“xttblog”,添加助理微信拉你进群。备注错误不会赞成好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合做可添加助理微信进行沟通!

本文分享自微信公众号 - 业余草(yyucao)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索