【问题标题】:lock and unlock in multi thread java在多线程java中锁定和解锁
【发布时间】:2021-03-07 06:37:35
【问题描述】:

我在我的代码中使用锁定和解锁并启动一些客户和生产者线程。 行 lock.waite 抛出 IllegalMonitorStateException。为什么? 加了锁,一个Thread不提供使用这个列表的条件?

 static class Customeer extends Thread {
            private List<String> list;
            private Lock lock;
            public Customeer(List<String> list, Lock lock) {
                this.list = list;
                this.lock = lock;
            }
            @Override
            public void run() {   
                lock.lock();
                if (list.size() == 0) {
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                    list.remove(0);
                    lock.unlock();
            }
        }
    
        static class Producer extends Thread {
            private List<String> list;
            private Lock lock;
            public Producer(List<String> list, Lock lock) {
                this.list = list;
                this.lock = lock;
            }
            @Override
            public void run() {
                    lock.lock();
                    list.add("hello");
                    list.notify();
                    lock.unlock();
            }
        }

【问题讨论】:

    标签: java multithreading locking


    【解决方案1】:

    您的代码存在一些问题,即:

    1. list.wait(); 除非您在同步方法(或块代码)中,否则您无法获取列表的监视器。

    2. list.notify();,除非您在同步方法(r 块代码)中,否则您不能释放列表的监视器。

    您不能在非同步方法或部分中使用 .wait().notify()

    像 sn-p 那样更改你的代码:

     static class Customeer extends Thread {
                private List<String> list;
                private Lock lock;
                public Customeer(List<String> list, Lock lock) {
                    this.list = list;
                    this.lock = lock;
                }
                @Override
                public void run() {   
                    lock.lock();
                    if (list.size() != 0) {
                       list.remove(0);
                    }                      
                    lock.unlock();
                }
            }
        
            static class Producer extends Thread {
                private List<String> list;
                private Lock lock;
                public Producer(List<String> list, Lock lock) {
                    this.list = list;
                    this.lock = lock;
                }
                @Override
                public void run() {
                        lock.lock();
                        list.add("hello");                    
                        lock.unlock();
                }
            }
    

    这些字符串正在调用IllegalMonitorStateException

    【讨论】:

    • 你的意思是锁不像同步块那样工作?
    【解决方案2】:

    线lock.wait 抛出IllegalMonitorStateException。为什么?

    其实并没有这样的行。

    但是,有一条线路调用list.wait()。而是你的问题的原因。

    为了在对象上调用wait(),您必须首先持有该对象上的原始互斥锁。您只能使用synchronized 获得那种类型的锁。 (synchronized 方法或 synchronized 块。)

    在你的情况下:

    • 您正在List 实例上调用wait
    • 您正在锁定 Lock 实例。
    • 您为Object.wait 持有错误类型的锁。您持有的是Lock 锁,而不是原始互斥锁。

    所以...如果您想在Lock 实例上执行等价的等待和通知,那么您需要调用Lock.newCondition() 来获取Condition 对象。然后你像这样使用它:

    private final Lock lock = ...
    private final Condition cond = lock.newCondition();
    
    try {
        lock.acquire();
        while (!the_condition_we_are_waiting_for) {
            cond.await();
        }
        // do stuff
    } finally {
       lock.release();
    }
    

    作为参考,如果您将上面的内容重写为使用原始互斥体,则会如下所示。

    private final Object lock = new Object();
    
    synchronized(lock) {
        while (!the_condition_we_are_waiting_for) {
            lock.wait();
        }
        // do stuff
    }
    

    (您可以使用 any 对象作为锁,但最好使用隐藏的对象,并且不会被任何其他代码锁定。)


    总之,要么使用带有synchronizedObject.waitObject.notify* 的原始互斥体,要么使用带有Lock.acquireLock.releaseCondition.awaitCondition.signalLock。不要试图混合使用两种锁定和条件变量。

    【讨论】: