java - 如何从actionEvent监听器通知主线程

标签 java multithreading swing actionlistener

我正在主线程中创建 JFrame 的新对象并调用其调用 wait() 的函数。我想唤醒这个主线程。

  public static void main(String[] args) throws Exception {
        //some other large code
        var loginWin = new LoginWin();
        loginWin.setVisible(true);
        loginWin.waitForLogin();
        System.out.println("Login Finished");
        //code after login

    }

LoginWin 扩展了 JFrame 并具有带有这样的操作监听器的按钮

    login.bsubmit.addActionListener(actionEvent -> {
        dataRecived();
    });

dataRecived() 函数:-

private void dataRecived() {

    passwd = login.passwd.getPassword();
    username = login.username.getText();
    iphost = login.iphost.getText();
    port = 9999;
    try {
        Integer.parseInt(login.port.getText());
    } catch (Exception e) {
        e.printStackTrace();
    }
    notify();
}

但是当我单击 login.bsubmit 按钮时,我收到以下异常:-

Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
    at java.base/java.lang.Object.notify(Native Method)
    at smit.quiz.server.LoginWin.dataRecived(LoginWin.java:52)
    at smit.quiz.server.LoginWin.lambda$new$1(LoginWin.java:34)
    at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
    at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
    at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
    at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
    at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
    at java.desktop/java.awt.Component.processMouseEvent(Component.java:6632)
    at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
    at java.desktop/java.awt.Component.processEvent(Component.java:6397)
    at java.desktop/java.awt.Container.processEvent(Container.java:2263)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5008)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840)
    at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
    at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
    at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
    at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2762)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4840)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:389)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

最佳答案

抛出此异常是因为您调用 Object.notify()没有“持有对象监视器”,即从 synchronized block 外部或带有 synchronized 修饰符的实例方法:

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object's monitor.

Throws:
IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.

<小时/>

也就是说,尝试以未明确设计的方式从其他线程修改 swing 对象是一个坏主意,请参阅 swing package docs :

Swing's Threading Policy

In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread.

[...]

As all events are delivered on the event dispatching thread, care must be taken in event processing. In particular, a long running task, such as network io or computational intensive processing, executed on the event dispatching thread blocks the event dispatching thread from dispatching any other events. While the event dispatching thread is blocked the application is completely unresponsive to user input. Refer to SwingWorker for the preferred way to do such processing when working with Swing.

More information on this topic can be found in the Swing tutorial, in particular the section on Concurrency in Swing.

我建议阅读这些文档,它们包含几个示例,解释如何使用 swing 实现响应式 UI。

关于java - 如何从actionEvent监听器通知主线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56729928/

相关文章:

c# - .NET Entity Framework Core、依赖注入(inject)和线程的 DBContext System.ObjectDisposed 异常

java - 如何将 class1 的 setText 设置为 class2?

Java System.out 重定向问题

java - PaintComponents() 从未被调用

java - Android OpenGL 帧间黑屏

java - JMS/MQ 消息传递的独立应用程序?

c - 为什么 accept() 系统调用在关闭前一个连接套接字之前不接受新连接

c++ - C++中使用wxthread更新wxframe的内容

java - 在 Spring Framework (Mockito) 中模拟一个 void 方法

java - 如何在 Tomcat 上用 Java 实现(应用程序)代理?