为什么不在java中使用带锁的try?

我已经阅读了这个主题 , 这篇关于尝试使用资源锁定的博客文章 ,正如我脑海中浮现的那样。 但实际上,我更喜欢的是带锁尝试 ,我的意思是没有锁实例化。 它会让我们从冗长中解脱出来

lock.lock(); try { //Do some synchronized actions throwing Exception } finally { //unlock even if Exception is thrown lock.unlock(); } 

宁愿看起来像:

 ? implements Unlockable lock ; ... try(lock) //implicitly calls lock.lock() { //Do some synchronized actions throwing Exception } //implicitly calls finally{lock.unlock();} 

所以它不是TWR ,而只是一些样板清洁。

您是否有任何技术理由建议描述为什么这不是一个合理的想法?

编辑:澄清我建议和简单的synchronized(lock){}块之间的区别,检查此片段:

 import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Test { public static void main(String[] args) { ReentrantLock locker =new ReentrantLock(); Condition condition = locker.newCondition(); Thread t1 = new Thread("Thread1") { @Override public void run(){ synchronized(locker){ try { condition.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Thread1 finished"); } } } ; Thread t2 = new Thread("Thread2") { @Override public void run(){ synchronized(locker){ Thread.yield(); condition.signal(); System.out.println("blabla2"); } } } ; t1.start(); t2.start(); } } 

执行将导致IllegalMonitorStateException ,因此不会在synchronized块中隐式调用lock()和unlock()方法。

如果你不得不处理这样一个简单的案例,其中锁定/解锁的模式仅限于这样的狭窄范围,你可能不想使用更复杂的Lock类,可能只是使用synchronized关键字相反。 话虽这么说,如果出于某种原因你需要使用更复杂的Lock对象,那么在Lock周围创建一个包装器应该是相对简单的,它实现了AutoCloseable接口以便能够做到这一点。 例:

 class AutoUnlock implements AutoCloseable { private final Lock lock; public static AutoUnlock lock(Lock lock) { lock.lock(); return new AutoUnlock(lock); } public static AutoUnlock tryLock(Lock lock) { if (!lock.tryLock()) { throw new LockNotAcquiredException(); } return new AutoUnlock(lock); } @Override public void close() { lock.unlock(); } private AutoUnlock(Lock lock) { this.lock = lock; } } 

使用上面的包装器,您可以执行以下操作:

 try (AutoUnlock autoUnlock = AutoUnlock.lock(lock)) { // ... do whatever that requires the lock ... } 

话虽这么说,Lock类通常用于非常复杂的锁定场景,其中这不会特别有用。 例如,Lock对象可以锁定在类中的一个函数中,然后在另一个函数中解锁(例如,在响应传入的远程过程调用时锁定数据库中的行,然后解锁该行以响应后来的RPC),因此,具有这样的包装或制作Lock AutoCloseable本身对其实际使用方式的用途有限。 对于更简单的场景,仅使用现有的并发数据结构或使用synchronized更为常见。

此答案用于解释编辑的行为。 synchronized的目的是在线程进入块(等待它不可用时)时锁定给定对象的监视器,并在线程退出块时释放它。

Lock是一种更高层次的抽象。

Lock实现提供了比使用同步方法和语句获得的更广泛的锁操作。

您可以使用它来锁定方法边界。 synchronized不能这样做,所以Lock不能单独使用synchronized实现,也没有我见过的实现使用它。 相反,他们使用其他模式,比如比较和交换 。 他们使用它在一个Lock对象中primefaces地设置一个状态,该对象将某个线程标记为锁的所有者。

在您的代码段中,您尝试调用

 condition.signal(); 

在一个不拥有创建conditionLock的线程中。 javadoc说

当调用此方法时,实现可能(并且通常确实) 要求当前线程保持与此Condition关联的锁 。 实现必须记录此前提条件以及未保持锁定时所采取的任何操作。 通常, 将抛出exception,例如IllegalMonitorStateException

这就是这里发生的事情。

执行

 synchronized (lock) {} 

使当前线程锁定(然后释放) lock引用的对象上的监视器。 执行

 lock.lock(); 

使当前线程在lock引用的对象中设置一些状态, lock其标识为所有者。