将 tryLock() 与 wait() 和 notify()/notifyAll() 一起使用



我是线程新手,我正在尝试在这里采用混合方法。我有下面的代码。

if(lock.tryLock())
{
try
{
//do some actions
lock.notifyAll(); // error throwing line
}
finally
{
lock.unlock();
}
}

如果我像这样运行程序 非法监视器异常会在该错误抛出行上抛出。 但是如果我在如下所示的同步块中调用,它可以工作。

if(lock.tryLock())
{
try
{
//do some actions
synchronized ( lock )
{
lock.notifyAll(); 
}
}
finally
{
lock.unlock();
}
}

我的问题是因为我已经 tryLock 为 true,这是否意味着我已经得到了锁并且可以安全地调用 wait(( 和 notify(( 方法? 提前谢谢..

忘记这里的"混合方法",这是行不通的。

每个对象都有一个隐式锁。这包括 Lock 类的对象,如 ReentrantLock。调用等待和通知始终使用隐式锁,这些方法不使用要调用它们的 Lock 对象的锁定功能。等待、通知和通知所有方法在 Object 中声明为本机方法和最终方法。

要获得等待和通知才能工作,您必须在锁定对象上进行同步,并且通过 tryLock 等方法完成锁定将无关紧要,这最终会在功能上等同于final Object lock = new Object();,只是更令人困惑。

锁对象有自己的等价物,如果你使用的是java.util.concurrent.locks.Lock那么从锁中获取一个条件,并调用await(相当于wait(和signal/signalAll(相当于notify/notifyAll(。

使用 Lock 对象,您可以有多个条件,允许您发出等待锁定的线程子集的信号。因此,您不需要 signalAll,就像隐式锁定代码需要 notifyAll 一样多。

例如,如果你看一下 ArrayBlockingQueue 是如何实现的,它使用 ReentrantLock,消费者有一个条件,生产者有另一个条件:

/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;

构造方式

public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull =  lock.newCondition();
}

使用隐式锁的等效代码必须调用 notifyAll 以避免丢失通知,因为我们不知道通知的线程是生产者还是使用者,但通过单独的条件,我们知道哪种类型的线程将收到通知。例如,取消排队代码在 notFull 条件下调用信号,最多在一个线程上唤醒:

/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.
*/
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return x;
}

最新更新