【问题标题】:Java ReentrantLock.unlock/await()/signal() not throwing IllegalMonitorStateExceptionJava ReentrantLock.unlock/await()/signal() 不抛出 IllegalMonitorStateException
【发布时间】:2014-08-03 13:35:02
【问题描述】:

我哪里错了?即使我的消费者线程没有持有锁,程序也不会为任何锁调用(解锁/等待/信号)抛出 IllegalMonitorStateException。

更新:

private final ReentrantLock lock = new ReentrantLock();
private final Condition producers = lock.newCondition();
private final Condition consumers = lock.newCondition();

@Override
public void run() {

    while (true) {
        try {
            //lock.lockInterruptibly();
            try {
                while (sharedResource.isEmpty()) {
                    printErr(name + " : Queue Empty ..");
                    consumers.await(500, TimeUnit.MILLISECONDS);
                }

                String obj = sharedResource.remove(0);
                printOut(name + " : " + obj);
                if (obj.equals(POISON_PILL)) {
                    sharedResource.add(POISON_PILL);
                    // System.err.println(name +" Taking break");
                    break;
                }

                producers.signal();
            } finally {
                lock.unlock();
            }
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // if(debug)System.err.println("Consumer Looping");
    }
}

void java.util.concurrent.locks.ReentrantLock.unlock()

根据 Java Doc。 公共无效解锁() 尝试释放此锁。 如果当前线程是这个锁的持有者,那么持有计数就会递减。如果保持计数现在为零,则释放锁。 If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

【问题讨论】:

  • 这看起来像 Java 代码。为什么你也用c#标记它?
  • 他们为什么会抛出异常?

标签: java multithreading locking


【解决方案1】:

这个问题似乎是基于一些不正确的假设/陈述。

  1. Java ReentrantLock 类没有 awaitsignal 方法。

  2. 这意味着consumers(很可能)不是ReentrantLock ...并且您的代码sn-p中没有任何内容调用signal(或singnal(原文如此))。

  3. 根据 javadoc,ReentrantLock 锁定和解锁方法不会抛出 IllegalMonitorStateException。而且我不希望他们这样做,因为 lock 和 unlock 方法不是作为原始监视器/互斥锁运行的。

AFAIK,从Lock 对象中获取该异常的唯一方法是使用原始互斥操作waitnotify ...这似乎是对Lock 对象的不正当使用。 (如果你想使用这些操作,any 对象就足够了,包括一个普通的 Object 实例。)

Lock 类旨在提供与 Java 原始锁正交的锁定,并且不限于严格的块结构。它们不直接提供等待和信号。如果需要,您需要创建一个Condition;例如使用Lock.newCondition()。请注意,如果当前线程不持有 Lock,则 Condition.await 和信号方法通常将抛出 IllegalMonitorStateException ...但该行为是特定于实现的;见javadoc


所以假设consumersCondition,那么它可能不会抛出异常有几个原因:

  1. 它可能不是 lock 表示的 Lock 的条件。

  2. 实际的Lock 类可能会提供不需要持有锁的Condition 对象...

很遗憾,您的代码 sn-p 缺少一些可以解决这些问题的重要线索。


更新

我将你的代码转换成我可以运行的东西:

package test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Lochy {

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition producers = lock.newCondition();
        Condition consumers = lock.newCondition();

        while (true) {
            try {
                try {
                    for (int i = 0; i < 3; i++) {
                        System.out.println("wait " + i);
                        consumers.await(500, TimeUnit.MILLISECONDS);
                    }
                    producers.signal();
                } finally {
                    lock.unlock();
                }
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

当我运行它时,我在unlock 看到一个IllegalMonitorStateException

当我注释掉unlock() 时,我在await 看到IllegalMonitorStateException

事后看来,很清楚发生了什么。 IllegalMonitorStateException 在这两种情况下都由await 抛出,但是当你在finally 块中调用unlock() 时,会抛出另一个IllegalMonitorStateException ...所以你看不到第一个。

简而言之,这些方法的行为与规范所说的完全一样。

【讨论】:

  • 更新了我的帖子。消费者和生产者是条件。根据 java 文档,如果当前线程没有持有锁,则调用以 throw IllegalMonitorStateException 解锁。
猜你喜欢
  • 2011-08-17
  • 2013-08-15
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2021-06-25
相关资源
最近更新 更多