繁体   English   中英

IllegalMonitorStateException在其run方法内部的线程上调用wait()(无同步块)

[英]IllegalMonitorStateException calling wait() on a thread inside its run method (with no synchronized block)

我要确保在套接字关闭时停止从套接字读取数据的线程(由于socket.isClosed()不能按预期工作),我写了一个“心跳”来检查套接字是否仍然存在打开。 刚好在BufferedReader开始读取套接字之前调用startHeartbeat()方法,并且仅在isClosed()为false时才开始读取方法。

这里有一些同步方法在起作用,但是与其他类似问题不同, wait()调用不在这些方法之一内。 这是基本代码:

synchronized boolean isClosed()
{
    return closed;
}

synchronized void setClosed(boolean b)
{
    closed = b;
}

//We need to make sure that the socket is still online, to ensure the reading stops when the connection closes.
void startHeartbeat()
{
    Thread heartbeat = new Thread()
    {
        public void run()
        {
            while (true)
            {
                try
                {
                    post(THUMP_THUMP);
                    setClosed(false);
                }
                catch (IOException e)
                {
                    setClosed(true);
                }
                finally
                {
                    try
                    {
                        this.wait(PULSE); //Exception here!
                    }
                    catch (InterruptedException e) {}
                }
            }
        }
    };
    heartbeat.setDaemon(true);
    heartbeat.start();
}

THUMP_THUMP只是发出的常量字符串( post()方法只是将对象写到BufferedWriter ),而PULSE是拍子之间的时间。

在读取各种线程(我理解它们为何具有异常)并读取该异常的API之后,我不确定为什么这里有一个IllegalMonitorStateException 有人可以告诉我我在做什么错吗?

有人可以告诉我我在做什么错吗?

是的-您没有在等待的对象上进行同步。 API文档非常清楚:

抛出:
IllegalMonitorStateException如果当前线程不是对象监视器的所有者。

重要的是要理解“对象所有者的监视者”基本上意味着“处于使用该对象的同步块中”。 同步块在开始时获取相关对象的监视器,并在结束时释放它。 Java同步教程

同步是围绕称为内部锁定或监视器锁定的内部实体构建的。 (API规范通常将此实体简称为“监视器”。)内在锁在同步的两个方面都起作用:强制对对象状态的独占访问并建立对可见性至关重要的事前关联。

每个对象都有一个与之关联的固有锁。 按照约定,需要对对象的字段进行独占且一致的访问的线程必须在访问对象之前先获取对象的固有锁,然后在完成对它们的锁定后释放固有锁。 据称,线程在获取锁和释放锁之间拥有内部锁。 只要一个线程拥有一个内在锁,其他任何线程都无法获得相同的锁。 另一个线程在尝试获取锁时将阻塞。

...

当线程调用同步方法时,它将自动获取该方法对象的内在锁,并在方法返回时释放该内在锁。 即使返回是由未捕获的异常引起的,也会发生锁定释放。

...

创建同步代码的另一种方法是使用同步语句。 与同步方法不同,同步语句必须指定提供内部锁的对象[...]

在您的代码中,当前线程不是 this的所有者,因为您未同步-因此是异常。 必须同步-请记住, wait()释放监视器,然后在返回之前重新获取它。

作为一个侧面说明,我强烈建议不要使用一个Thread对象的监视器进行同步,等待通知等-内码Thread已经这样做,那么您的代码和它的代码很容易相互干扰。 我建议仅出于同步/等待/通知的目的创建单独的对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM