ReentrantLock比synchronized 强大在哪儿?

ReentrantLock比synchronized 强大在哪儿?

问题描述:

官方说明:一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。

强大在哪儿?求高人解释。

回楼主,其实提到了,Synchronized只能在方法或者块上加锁,而lock可以只对某条语句进行加锁。

再回楼主,您说的没有特别指出ReentrantLock的好处,其实我列举的三点应该都比较明显了:
1、在某些场合下,确实需要获得锁的时间与申请锁的时间相一致,但是Synchronized做不到。

2、如果不支持中断处理,那么线程可能一直无限制的等待下去,就算那些正在占用资源的线程死锁了,正在等待的那些资源还是会继续等待,但是ReentrantLock可以选择放弃等待。

3、关于Condition这个强大的特性都可以另开一贴了,建议仔细查看API。

synchronized锁的粒度比Lock的粗

举个简单的例子:

1、Lock的某些方法可以决定多长时间内尝试获取锁,如果获取不到就抛异常,这样就可以一定程度上减轻死锁的可能性,如果锁被另一个线程占据了,synchronized只会一直等待,很容易错序死锁

2、synchronized的话,锁的范围是整个方法或synchronized块部分;而Lock因为是方法调用,可以跨方法,灵活性更大

3、便于测试,单元测试时,可以模拟Lock,确定是否获得了锁,而synchronized就没办法了

简单说:
1、ReentrantLock可以实现fair lock
[code="java"]
public ReentrantLock(boolean fair) {
sync = (fair)? new FairSync() : new NonfairSync();
}
[/code]
所谓fair lock就是看获得锁的顺序是不是和申请锁的时间的顺序是一致的

2、ReentrantLock支持中断处理
[code="java"]
public final void acquireInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
[/code]
就是说那些持有锁的线程一直不释放,正在等待的线程可以放弃等待。

3、ReentrantLock可以和condition结合使用
[code="java"]
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
[/code]

[code="java"]
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
[/code]

ps Synchronized的性能随着JDK版本的升级变得越来越好,到了6以后,其实也不像网上传的那样性能比ReentrantLock差很多很多。

[quote]ReentrantLock实现了Lock接口。获得ReentrantLock的锁与进入synchronized块具有相同的语义,释放ReentrantLock锁与退出synchronized块有相同的语义。相比于synchronized,ReentrantLock提供了更多的灵活性来处理不可用的锁。下面具体来介绍一下ReentrantLock的使用。
1. 实现可轮询的锁请求
在内部锁中,死锁是致命的——唯一的恢复方法是重新启动程序,唯一的预防方法是在构建程序时不要出错。而可轮询的锁获取模式具有更完善的错误恢复机制,可以规避死锁的发生。
如果你不能获得所有需要的锁,那么使用可轮询的获取方式使你能够重新拿到控制权,它会释放你已经获得的这些锁,然后再重新尝试。可轮询的锁获取模式,由tryLock()方法实现。此方法仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值true。如果锁不可用,则此方法将立即返回值false。此方法的典型使用语句如下:
Lock lock = ...;
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}
2. 实现可定时的锁请求
当使用内部锁时,一旦开始请求,锁就不能停止了,所以内部锁给实现具有时限的活动带来了风险。为了解决这一问题,可以使用定时锁。当具有时限的活
动调用了阻塞方法,定时锁能够在时间预算内设定相应的超时。如果活动在期待的时间内没能获得结果,定时锁能使程序提前返回。可定时的锁获取模式,由tryLock(long, TimeUnit)方法实现。
3. 实现可中断的锁获取请求
可中断的锁获取操作允许在可取消的活动中使用。lockInterruptibly()方法能够使你获得锁的时候响应中断。[/quote]

[quote]当ReentrantLock被加入到Java 5.0中时,它提供的性能要远远优于内部锁。如果有越多的资源花费在锁的管理和调度上,那用留给应用程序的就会越少。更好的实现锁的方法会使用更少的系统调用,发生更少的上下文切换,在共享的内存总线上发起更少的内存同步通信。耗时的操作会占用本应用于程序的资源。Java 6中使用了经过改善的管理内部锁的算法,类似于ReentrantLock使用的算法,从而大大弥补了可伸缩性的不足。因此ReentrantLock与内部锁之间的性能差异,会随着CPU、处理器数量、高速缓存大小、JVM等因素的发展而改变。[/quote]

[color=red]PS:以上摘自[/color]