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

标签 java multithreading locking thread-synchronization

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

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

如果我像这样运行程序,则会在该错误抛出行抛出非法监视器异常。但是如果我像下面这样在同步块(synchronized block)中调用,它就可以工作。

if(lock.tryLock())
{
    try
    {
        //do some actions

        synchronized ( lock )
        {
            lock.notifyAll(); 
        }
    }
    finally
    {
        lock.unlock();
    }
}

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

最佳答案

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

每个对象都有一个隐式锁。这包括像 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(等价于等待)和 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;
}

关于java - 将 tryLock() 与 wait() 和 notify()/notifyAll() 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52990630/

相关文章:

java - 使用 VScode 的 Spring-Boot 应用程序运行配置

php - C和php之间的锁定文件

c# - 为什么锁确保底层监视器被释放而直接使用监视器却没有?

java - 使用maven编译时将xml文件从src/复制到class/

Java Socket 不返回流中的任何内容

java - 当我请求整数时,如何检查用户输入是否包含字符串?

java - 为什么主线程不等待其他异步进程(线程)完成。 allOff 无法正常工作

java - 聚合线程和线程优先级(java)

Java 简单单线程 IllegalMonitorStateException

c - 从不同进程强制移除 fcntl 锁