Java:swing工作线程同步

时间:2012-07-13 13:48:26

标签: java multithreading synchronization swingworker

在我的应用程序中,我有一个文本字段和一个按钮。从文本字段丢失焦点后,第一个摇摆工作者(假设它为sw1)被调用。这会打开一个弹出窗口以填充值以放入文本字​​段。在用户单击按钮后调用第二个swing工作者(假设它为sw2)。 现在的问题是,如果我在文本字段中写入内容然后单击按钮,则首先启动sw1以计算要放入文本字​​段的值,同时也启动sw2。并且sw2首先完成,然后sw1填充结果。我想要的是sw2应该等待sw1完成。一旦sw1完成任务,它将通知sw2。 我通过互联网和stackoverflow引用了很多引用。 This是几乎符合我要求的那个。 我试图在类中创建一个静态的final对象,它启动sw1:

public final static Object lockObject = new Object();

然后在sw1的done()方法中,我编写了如下代码:

synchronized(lockObject) {
        sw1.notifyAll();
}

第二个类的doInBackground()方法,在第一行,我编写了如下代码:

synchronized(FirstClass.lockObject) {
    try {
        sw2.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

但是我在java.lang.Object.notifyAll(Native Method)中得到了java.lang.IllegalMonitorStateException。任何人都可以告诉我这是什么问题,以及如何让它按照我想要的方式运作。

更新:根据欧内斯特的解决方案,我修改了我的代码,它现在看起来像:

    FirstClass.java

    public final static Object lockObject = new Object();

    public static boolean flag = false;

    someMethod() {
        synchronized(lockObject){
            sw1.doInbackground() {
            ......
            }

            sw1.done() {
            .....
            flag = true;
            lockObject.notifyAll();
            }

        }
    }


    SecondClass.java

    anotherMethod() {
        sw2.doInbackground() {
            try {
                while (!FirstClass.flag) {
                    FirstClass.lockObject.wait();
                }
                FirstClass.flag = false;
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ......
        }

    }

但是我仍然在lockObject.notifyAll()行上获得java.lang.IllegalMonitorStateException。你能否告诉我,我是否正确行事?

感谢。

3 个答案:

答案 0 :(得分:2)

您的代码看起来应该是这样的。

FirstClass.java

public final static Object lockObject = new Object();

public static boolean flag = false;

someMethod() {
    sw1.doInbackground() {
    ......
    }

    sw1.done() {
    .....
    }

    synchronized(lockObject){
        flag = true;
        lockObject.notifyAll();
    }
}


SecondClass.java

anotherMethod() {
    sw2.doInbackground() {
        try {
            synchronized(lockObject){
                while (!FirstClass.flag) {
                    FirstClass.lockObject.wait();
                }
                FirstClass.flag = false;
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        ......
    }

}

但是。如果您有多个FirstClass.java和SecondClass.java实例,则在全局静态对象上进行同步将使您遇到麻烦。你应该找到一种传递对象实例的方法。

如果我理解了你的用例,你不能简单地在用户开始编辑字段时禁用sw2按钮,并在第一个工作完成后重新启用它吗?对用户来说也会更清楚。

答案 1 :(得分:2)

您无需重新发明这样一个简单的同步工具。例如,您可以使用CountDownLatch。 Sw1做倒计时和sw2 - 等待。

答案 2 :(得分:1)

您只能在您持有其监视器的对象上调用wait()notify()。在每个代码片段中,您将锁定一个对象,但在另一个对象上调用这些方法。它只是不起作用。我担心我无法弄清楚你想要做什么,所以很难给你特定的修正,但基本上,这些块需要看起来像

synchronized(sw2) {
    try {
        sw2.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

假设有两个线程,T1和T2,还有一些对象O1。然后,如果在线程T1上运行的代码想要等到线程T2中的代码表示可以继续,则它必须在对象O1上同步,然后调用O1.wait()。当在T2上运行的代码想要将该消息发送到T1时,它必须在O1上同步并调用O1.notify()(或O1.notifyAll()。)对于{{{{{ 1}},但两个线程中的代码必须同意使用相同的对象。