线程问题

时间:2009-02-25 00:14:48

标签: java multithreading user-interface

*我正在使用Java。

我有这个线程,代理,探索一个房间来确定它的大小,如果它很脏就清理它。然后我有了界面,它在探索环境时绘制代理。 Agent是Thread的子类,Java负责管理线程。我所做的就是创建线程并说出object.start()。

这在正常情况下非常有效。但是,在此期间启用菜单,这意味着用户可以在代理正在探索时弄乱房间。这不应该发生。

因此,一旦用户点击告诉代理清理房间的选项,我想禁用所有菜单。除非它不能正常工作。这是问题所在:

...
public void ActionPerformed(ActionEvent e)
{
    //disable the menus with setEnabled(false);
    agent.start();
    //enable the menus with setEnabled(true);
}

问题是在代理程序线程执行其功能之前启用了菜单。我想过使用Thread.join() - 这可以保证启用菜单的代码只在代理程序线程结束后执行。但是,如果我使用Thread.join(),代理移动时接口不会自动更新,因为它正在等待代理完成!

我已经考虑过从代理中禁用接口,然后在代理完成后启用它,但我不确定它是否会起作用,这里最大的问题是代理不应该乱用菜单。

所以,总而言之,我需要一个执行更新接口的线程/绘制代理移动,但该线程不能与启用菜单相同。目前似乎有一个线程同时执行这两个操作。假设这是可能的而不是太复杂。

4 个答案:

答案 0 :(得分:5)

  

我考虑过禁用   然后从代理接口   代理完成后启用它,   但我不确定那会起作用   这里最大的问题是   代理人不应该搞乱   菜单。

您可以让代理调用GUI类中的一个方法,该方法在完成后重新启用菜单。当然,该方法将在EDT上调用适当的Swing方法。

class Agent extends Thread
{
    @override
    public void run()
    {
       // run around the room

       // finally done
       gui.agentIsDone();
    }
}

class GUI extends JFrame
{
    ...

    void agentIsDone()
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @override 
            public void run()
            {
                menus.setEnabled(true);
            }
        });
    } 
}

如果多个代理可以同时运行,则需要在重新启用菜单之前检查是否所有代理都已完成。

答案 1 :(得分:2)

听起来你需要你的代理人发出通知(有人还使用Observer / Observable吗?)到您的界面,清洁已经开始并完成了。您的界面会在收到这些通知后分别致电setEnabled(false)setEnabled(true)

编辑:这个想法是将菜单的操作与代理的执行分开。即除了菜单项之外,如果您引入另一种方式来启动清洁会发生什么?在这种情况下,您可能仍希望禁用菜单。

答案 2 :(得分:1)

在你的actionPerformed方法中,只需禁用菜单然后启动线程即可 - 但是你不应该在同一个功能中再次启用菜单。相反,您需要在线程完成时触发菜单的启用。我建议,在代理线程结束时,使用Runnable调用SwingUtilities.invokeLater()将重新启用菜单。

答案 3 :(得分:0)

在启动线程之前禁用菜单。完成后,线程需要在控制器上调用某些方法,并在该方法中再次启用菜单。代理人不会搞乱菜单;它只会在控制器完成时通知它。当控制器知道代理已完成时,控制器将启用菜单。

另外,据推测,继承Thread是不好的做法。您应该实现Runnable,然后创建一个以Runnable为目标的Thread,并启动该线程。这样,如果您的代理是Runnable,您可以在自己的线程中运行它,或者在主线程中运行它(通过简单地调用run())或在线程池中运行它。