Java Condition 在await() 返回后无法重新获取与其关联的锁(ReentrantLock)

标签 java locking conditional-statements

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

class Foo {
    private ReentrantLock _lock;
    private Condition _cond;
    private Thread _thr;
    private LinkedList<String> _msgQueue;

    public Foo() {
        _lock = new ReentrantLock();
        _cond = _lock.newCondition();
        _msgQueue = new LinkedList<String>();
        startThread();
    }

    public void putMsg(String msg) throws Exception {
        _lock.lock();
        _msgQueue.addLast(msg);
        _cond.signal();
        System.out.println(Thread.currentThread().getId() + ": Signal write thread.");
        _lock.unlock();
        System.out.println(Thread.currentThread().getId() + ": Unlocked.");
    }

    private void startThread() {
        _thr = new Thread() {
            public void run() {
                _lock.lock();
                while(true) {
                    try {
                        while (!_msgQueue.isEmpty()) {
                            String msg = _msgQueue.getFirst();
                            System.out.println(msg);
                            _msgQueue.removeFirst();
                        }

                        System.out.println(Thread.currentThread().getId() + ": getHoldCount:" + _lock.getHoldCount());
                        System.out.println((Thread.currentThread().getId() + ": isLocked:" + _lock.isLocked()));
                        System.out.println(Thread.currentThread().getId() + ": isHeldByCurrentThread:" + _lock.isHeldByCurrentThread());
                        System.out.println(Thread.currentThread().getId() + ": Awaiting...");

                        _cond.await();

                        System.out.println(Thread.currentThread().getId() + ": Write thread awaken");

                    } catch (Exception e) {
                        e.printStackTrace();
                        break;
                    } finally {
                        try {
                            _lock.unlock();
                        } catch (Exception e) {
                        }
                    }
                }
                System.out.println("Write thread exit.");
            }
        };

        _thr.start();
    }
}

public class LockTest {
    public static void main(String[] args) throws Exception {
        Foo foo = new Foo();
        foo.putMsg("Msg 1");
        foo.putMsg("Msg 2");
        Thread.sleep(1000);
        foo.putMsg("Msg 3");
    }
}

The code output after one running:
1: Signal write thread.
1: Unlocked.
1: Signal write thread.
1: Unlocked.
Msg 1
Msg 2
8: getHoldCount:1
8: isLocked:true
8: isHeldByCurrentThread:true
8: Awaiting...
1: Signal write thread.
1: Unlocked.
8: Write thread awaken
Msg 3
8: getHoldCount:0
8: isLocked:false
8: isHeldByCurrentThread:false
8: Awaiting...
Write thread exit.
java.lang.IllegalMonitorStateException at

java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source) at

java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source) at 

java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(Unknown Source) at 

java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source) 

at Foo$1.run(LockTest.java:44)

问题是: 根据http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#await() ,当线程返回时,保证持有该锁。但从输出中我们看到await()返回后,它并没有重新获取锁。这是一个错误还是我犯了一些错误?

最佳答案

According to http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#await(), when the thread returns it is guaranteed to hold this lock.

确实如此,但它也说线程在调用方法之前必须持有锁:

The current thread is assumed to hold the lock associated with this Condition when this method is called. It is up to the implementation to determine if this is the case and if not, how to respond. Typically, an exception will be thrown (such as IllegalMonitorStateException) and the implementation must document that fact.

这与“普通”监视器(Object#wait)的工作方式相同:开始等待时必须持有锁(在 Object#wait 的情况下使用同步块(synchronized block),此处使用 Lock#lock)。然后锁将被释放,您等待。当等待结束时,你也再次持有锁。

关于Java Condition 在await() 返回后无法重新获取与其关联的锁(ReentrantLock),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17824875/

相关文章:

c - 如何锁定文件以进行 O_RDWR 的读写访问

c# - 我想知道有没有更好的方法来实现这个 "simple lock"

python - 基于条件的索引范围

java - 我该如何解决这个 java.lang.OutOfMemoryError : Java heap space?

java - 如何监控文本java fx 中的打印持续时间?

mysql - MySQL InnoDB 表的恒定锁等待超时

java - 在一个 if 语句中使用多个 OR 条件是否正确,有哪些替代方案?

r - 多个条件下的子集

java - 在 Java 中生成 PKCS#1 格式的 RSA key

java - 不使用 Hibernate 创建表