Java 多线程同步问题的探究(三、Lock来了,大家都让开【2. Fair or Unfair? It is a question...】)
让我们继续前面有关ReentrantLock的话题。
首先,ReentrantLock有一个带布尔型参数的构造函数,在JDK官方文档中对它是这样描述的:
“此类的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock? 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。 ”
简单来讲:公平锁使线程按照请求锁的顺序依次获得锁;而不公平锁则允许讨价还价,在这种情况下,线程有时可以比先请求锁的其他线程先得到锁。
观察采用公平锁和非公平锁的例程运行效果发现:线程获得锁的顺序发生了一些变化(见下表)。
单CPU情况下,同步、非公平锁和公平锁的吞吐量:

可以看到,同步和公平锁的吞吐量都是最低的,公平锁更低一些。但是同步内置的监控器锁是不公平的,而且永远都是不公平的。而JVM保证了所有线程最终都会得到它们所等候的锁。确保统计上的公平性,对多数情况来说,这就已经足够了,而这花费的成本则要比绝对的公平保证的低得多。
转载注明出处:http://x-spirit.iteye.com/、http://www.blogjava.net/zhangwei217245/
既然Lock这么近乎完美,那我们也许可以忘却synchronized了。
但是任何事物都是有两面性的。
1.使用Lock,你必须手动的在finally块中释放锁。锁的获得和释放是不受JVM控制的。这要求编程人员更加细心。
2.当 JVM 用 synchronized 管理锁定请求和释放时,JVM在生成线程转储时能够包括锁定信息。这些对调试非常有价值,因为它们能标识死锁或者其他异常行为的来源。
Lock
类只是普通的类,JVM 不知道具体哪个线程拥有Lock
对象。转载注明出处:http://x-spirit.iteye.com/、http://www.blogjava.net/zhangwei217245/
Lock提供了在多线程争用的情况下更好的并发性,但这是以牺牲一定的可维护性为代价的。
转载注明出处:http://x-spirit.iteye.com/、http://www.blogjava.net/zhangwei217245/
所以说,当大量线程发生争用的时候,Lock来了,大家都让开。