将 tryLock() 与 wait() 和 notify()/notifyAll() 一起使用
using tryLock() together with wait() and 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() 方法?
提前致谢..
忘记这里的"hybrid approach",这个不行。
每个对象都有一个隐式锁。这包括像 ReentrantLock 这样的 Lock 类 对象。调用 wait 和 notify 总是使用隐式锁,这些方法不使用您调用它们的 Lock 对象的锁定功能。 wait、notify 和 notifyAll 方法在 Object 中声明为 native 和 final。
要让 wait 和 notify 工作,你必须在锁定对象上同步,并且通过 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;
}
我是线程处理的新手,我正在尝试在这里采用混合方法。我有以下代码。
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() 方法? 提前致谢..
忘记这里的"hybrid approach",这个不行。
每个对象都有一个隐式锁。这包括像 ReentrantLock 这样的 Lock 类 对象。调用 wait 和 notify 总是使用隐式锁,这些方法不使用您调用它们的 Lock 对象的锁定功能。 wait、notify 和 notifyAll 方法在 Object 中声明为 native 和 final。
要让 wait 和 notify 工作,你必须在锁定对象上同步,并且通过 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;
}