2009-02-25 2 views
2

* Я использую Java.Проблема с потоками

У меня есть эта тема, агент, которая исследует комнату, чтобы определить ее размер, и очистить ее, если она грязная. Тогда у меня есть интерфейс, который привлекает агента при исследовании среды. Агент подклассифицирован из 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(), интерфейс не обновляется сам, пока агент движется, потому что он ждет завершения действия агента!

Я думал об отключении интерфейса от агента, а затем включил его, как только агент будет выполнен, но я не уверен, что это сработает, и самая большая проблема здесь заключается в том, что агент не должен возиться с меню.

Итак, чтобы подвести итог, мне нужен поток, выполняющий обновление интерфейса/перенос агента, но этот поток не может быть тем же самым, что и в меню. Кажется, что в настоящее время существует один поток, выполняющий оба. Предполагая, что это возможно и не слишком сложно.

ответ

5

Я думал об отключении интерфейса от агента, а затем позволяет ему после того, как агент будет сделано, , но я не уверен, что будет работать и самой большой проблемой здесь является то, что агента не следует возиться с меню .

Вы можете заставить агента вызвать метод в классе GUI, который снова включает меню, когда это будет сделано. Разумеется, этот метод вызовет соответствующие методы Swing на EDT.

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); 
      } 
     }); 
    } 
} 

Если несколько агентов могут работать одновременно, вам нужно проверить, если все они сделаны, прежде, чем снова включить в меню.

+0

только то, что я искал (чистое взаимодействие от рабочего потока к графическому интерфейсу) –

1

В вашем методе actionPerformed было бы просто отключить меню, а затем запустить поток, но вы не должны снова включать меню в ту же функцию. Скорее всего, вам нужно вызвать включение меню при завершении потока. Я бы предложил в конце потока вашего агента позвонить SwingUtilities.invokeLater() с Runnable, который будет повторно использовать меню.

2

Похоже, вам необходимо, чтобы ваш агент выдавал уведомление (кто-нибудь еще использует Observer/Observable?), Чтобы ваш интерфейс начал и закончил очистку. Ваш интерфейс будет, соответственно, звонить setEnabled(false) и setEnabled(true), когда он получит эти уведомления.

EDIT: Идея состоит в том, чтобы отделить управление меню от выполнения агента. То естьчто произойдет, если вы представите другой способ инициировать очистку, кроме пункта меню? Вероятно, вы все равно хотите, чтобы меню было отключено в этом случае.

+0

Надеюсь, люди не используют Observer/Observable. Это может быть желаемое за действительное. Они должны иметь большой @deprecated на них. –

+0

Справедливо. :) Я больше пытался указать, что Агент должен давать уведомление о запуске/остановке, вместо того, чтобы GUI неявно знал, что такое деятельность агента. – JMD

0

отключите меню перед началом потока. Поток должен вызвать какой-либо метод на вашем контроллере, когда он будет сделан, и в этом методе вы снова включите меню. Агент не будет возиться с меню; он будет просто уведомлять контроллер, когда это будет сделано. Контроллер включит меню, когда узнает, что агент выполнен.

Кроме того, предположительно, это не очень хорошая практика для подкласса Thread. Вместо этого вы должны использовать Runnable, а затем создать Thread с вашим Runnable в качестве своей цели и запустить поток. Таким образом, если ваш агент является Runnable, вы можете запускать его в своем потоке или в основном потоке (просто вызывая run()) или в пуле потоков и т. Д.

Смежные вопросы