我试图了解是什么使并发锁如此重要,如果可以使用的话synchronized (this)。在下面的虚拟代码中,我可以执行以下任一操作:
synchronized (this)
同步了整个方法或同步了易受攻击的区域(synchronized(this){...}) 或使用ReentrantLock锁定易受攻击的代码区域。 码:
synchronized(this){...}
private final ReentrantLock lock = new ReentrantLock(); private static List<Integer> ints; public Integer getResult(String name) { . . . lock.lock(); try { if (ints.size()==3) { ints=null; return -9; } for (int x=0; x<ints.size(); x++) { System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x)); } } finally { lock.unlock(); } return random; }
一个ReentrantLock的是非结构化的,不像synchronized结构-即你不需要使用块结构锁,甚至可以举行跨越方法的锁。一个例子:
synchronized
private ReentrantLock lock; public void foo() { ... lock.lock(); ... } public void bar() { ... lock.unlock(); ... }
这样的流程不可能通过synchronized构造中的单个监视器来表示。
除此之外,还ReentrantLock支持锁定轮询和支持超时的可中断锁定等待。ReentrantLock还支持可配置的公平性策略,从而允许更灵活的线程调度。
ReentrantLock
此类的构造函数接受一个可选的fairness参数。设置为set时true,在争用条件下,锁倾向于授予对等待时间最长的线程的访问。否则,此锁不能保证任何特定的访问顺序。使用许多线程访问的公平锁的程序可能会比使用默认设置的程序显示较低的总体吞吐量(即,速度较慢;通常要慢得多),但获得锁并保证缺乏饥饿的时间差异较小。但是请注意,锁的公平性不能保证线程调度的公平性。因此,使用公平锁的多个线程之一可能会连续多次获得它,而其他活动线程没有进行且当前未持有该锁。另请注意,未定时tryLock方法不遵循公平性设置。如果锁定可用,即使其他线程正在等待,它将成功。
true
tryLock
ReentrantLock 可能还具有更高的可扩展性,在更高的竞争条件下表现更好。你可以在此处了解更多信息。
但是,此主张遭到了质疑;看到以下评论:
在可重入锁测试中,每次都会创建一个新锁,因此没有互斥锁,并且结果数据无效。另外,IBM链接不提供基础基准测试的源代码,因此无法描述测试是否正确进行。
什么时候应该使用ReentrantLocks?根据该developerWorks文章…
ReentrantLocks
答案很简单-在你实际需要它提供的东西时synchronized,例如定时锁等待,可中断锁等待,非块结构锁,多个条件变量或锁轮询,请使用它。ReentrantLock它还具有可伸缩性的好处,如果你实际遇到竞争激烈的情况,则应使用它,但是请记住,绝大多数synchronized块几乎从未表现出任何竞争,更不用说竞争激烈了。我建议你进行同步开发,直到证明同步不足为止,而不是简单地假设“性能会更好”。ReentrantLock。请记住,这些是面向高级用户的高级工具。(而且,真正的高级用户倾向于使用他们能找到的最简单的工具,直到他们确信简单的工具是不合适的。)和往常一样,首先使其正确,然后再担心是否必须使其更快。