正常模式用的ReentrantLock和锁()/解锁()是这样的:是否同步锁定一个Reentrantlock,或只有它的对象?
lck.lock();
try {
// ...
}
finally {
lck.unlock();
}
可以这样重构为
synchronized(lck) {
// ...
}
?
为什么?
正常模式用的ReentrantLock和锁()/解锁()是这样的:是否同步锁定一个Reentrantlock,或只有它的对象?
lck.lock();
try {
// ...
}
finally {
lck.unlock();
}
可以这样重构为
synchronized(lck) {
// ...
}
?
为什么?
这些是不同的东西。内置于语言中,可用于任何对象。它所做的是锁定其固有的锁定。每一个物体都有一个。由于它是一种内置机制,因此不需要try-finally
块 - 当控制器退出块时,锁始终处于解锁状态。所以只要你的代码实际上退出该块,锁就会被解锁。
ReentrantLock
是一个特殊的类。它锁定了一些特殊的内部对象,这可能是特定于实现的。它确实不是锁定其固有锁定。当然,你也可以锁定那一个,但它通常没有任何意义。这段代码几乎肯定会死锁,例如:
final ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
lock.lock();
try {
System.out.println("Thread 1 locked the lock");
try { Thread.sleep(100); } catch (Exception ex) {}
synchronized (lock) {
System.out.println("Thread 1 locked lock's intrinsic lock");
}
} finally {
lock.unlock();
}
}).start();
new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 locked lock's intrinsic lock");
try { Thread.sleep(200); } catch (Exception ex) {}
lock.lock();
try {
System.out.println("Thread 2 locked the lock");
} finally {
lock.unlock();
}
}
}).start();
它锁死,因为两个线程锁定不同的顺序两回事。
它当然感觉像ReentrantLock
几乎与一样。它的工作原理类似,但既方便又不太强大。所以除非你需要ReentrantLock
的任何功能,比如可中断的锁定尝试或锁定超时,你应该坚持使用来实现可重入锁定,并且使用任何对象(简单的new Object()
都可以)。
我假设您知道分别由Lock
和分别提供的显式和隐式锁定的差异。
我相信你正在寻找一个理由说什么是错的,使用内部实现块Lock
接口的类的实例,如synchronized(lock)
。
它可以重构吗? 是的。
但是你应该这样做吗? 不适用于实现Lock类接口的类实例
为什么? - 好的。
这是所有权利,如果你只是用lock
只有内但是你离开的可能性,其他开发者滥用代码例如说如果某人明天尝试在synchronized(lock)
之内调用Lock
方法,如下所示。
Lock lock = new ReentrantLock();
synchronized(lock){ //You write this
// lock.lock(); // I am not taking a lock here
System.out.println("See emily play");
...
...
... // after 100 lines of code
//callAnotherMethod(lock); //Someone else does this
lock.unlock(); //Someone else does this
}
上面的代码是可怕的,但给你一个例子,在上面的例子,如果你不叫lock()
,那么你最终IllegalMonitorStateException
。如果你打电话(取消以上注释)lock.lock()
它没有区别。
更不用说callAnotherMethod(lock)
您正在传递锁定实例以及它可以引入哪些意外行为。
请记住,就是这样一个例子。底线,如果任何机会都能正确工作,那只是在浪费资源和时间,并没有任何优势/目的。更重要的是,它不能保证它在将来不会引入回归。如果有任何这样的回归,由于滥用概念,最终可能会浪费大量时间。
软件始终采用开放式原则设计。你会写的代码会非常清楚地违反它。
在情况下,如果你想使用细粒度锁使用那么你可以让下面
Object obj1 = new Object();
Object obj2 = new Object();
public void doSomething(){
synchronised(obj1){
...
}
}
public void doSomethingMore(){
synchronised(obj2){
...
}
}
但随后的使用再一次,我看不出有任何理由,你为什么不使用多个锁实例来实现上述。
不,它不能。他们是不同的机制。 – EJP
可能重复的[synchronized和re-entrant lock之间的区别?](http://stackoverflow.com/questions/9072422/difference-between-synchronized-and-rentrant-lock) – jalopaba
不可以。锁之后的主要思想是为了避免粗粒度同步块 - IOW,它是对同步块的改进。如果你使用'synchronized(lck)',你基本上像对待任何其他对象一样对待lck,而不是真正使用锁定概念。 – Vasan