5

我已经阅读了这个主题,以及这篇关于尝试使用资源锁的博客文章,因为这个问题突然出现在我的脑海中。但实际上,我更愿意尝试使用 lock,我的意思是没有锁实例化。它会让我们从冗长的

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();
        }

}

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

4

2 回答 2

4

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

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 类通常用于非常复杂的锁定场景,而这并不是特别有用。例如,锁定对象可能被锁定在一个类的一个函数中,然后在另一个函数中解锁(例如,锁定数据库中的一行以响应传入的远程过程调用,然后解锁该行以响应稍后的 RPC),因此,拥有这样一个包装器或制作一个 Lock AutoCloseable 本身,对于它的实际使用方式来说是有限的。对于更简单的场景,更常见的是只使用现有的并发数据结构或使用同步。

于 2014-10-18T02:16:55.460 回答
0

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

Lock是更高层次的抽象。

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

您可以使用它来锁定方法边界。synchronized无法做到这一点,因此 aLock不能单独实现,synchronized而且我见过的任何实现都没有使用它。相反,他们使用其他模式,例如compare 和 swap。他们使用它在Lock对象中原子地设置状态,将某个线程标记为锁的所有者。

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

condition.signal();

在不拥有创建的线程Lockconditionjavadoc状态_

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

这就是这里发生的事情。

执行

synchronized (lock) {}

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

lock.lock();

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

于 2014-10-18T03:00:52.867 回答