2010-09-12 3 views
2

У меня есть следующая проблема. Приложение J2ME полностью мертво. Я, хотя это был тупик, но используя встроенные функции NetBeans, он не смог найти такого.Проблемы с потоками в Java

Через некоторое время, однако, он начал бросать следующие сообщения в консоли:

8242276 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242284 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242292 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242340 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242540 - CORE - CRITICAL - 2 - **event queue 3 full, dropping event
8242628 - CORE - CRITICAL - 1 - **event queue 3 full, dropping event
8242636 - CORE - CRITICAL - 1 - **event queue 3 full, dropping event
8242644 - CORE - CRITICAL - 1 - **event queue 3 full, dropping event

и так далее.

Любые идеи относительно того, что может быть в случае, если это не тупик (в то время, как говорит NetBeans), будет очень признателен.

Спасибо!

ответ

2

Когда вы используете AWT или Swing, в фоновом режиме работает специальный поток, называемый EventQueue. Когда вы добавляете слушателя к компоненту (например, ActionListener в JButton) и метод прослушивателя событий (например, actionPerformed), метод выполняется в потоке EventQueue. Вы можете выбрать, чтобы выполнить что-то на резьбе EventQueue, когда текущий поток не EventQueue нить, запустив

EventQueue.invokeLater(new Runnable(){ //this could also be SwingUtilities.invokeLater() instead 
    public void run(){ 
     ... 
    } 
}); 

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

ActionListener l = new ActionListener(){ 
    public void actionPerformed(ActionEvent ae){ 
     try { 
      BufferedReader in = new BufferedReader(new FileReader("foo.txt")); 
      StringBuffer sb = new StringBuffer(); 
      char[] buf = new char[4096]; 
      int n; 
      while (-1 != (n = in.read(buf))){ 
       sb.append(buf, 0, n); 
      } 
      in.close(); 
      String s = sb.toString(); 
      jTextPane1.setText(s); 
     } catch (IOException ioe){ 
      ioe.printStackTrace(); 
     } 

    } 
}; 
jButton1.addActionListener(l); 

Весь код внутри actionPerformed выполняется на резьбе EventQueue. Никакие другие события не могли быть обработаны до тех пор, пока этот код не будет завершен. Если foo.txt - это большой файл, то до завершения кода он пройдет некоторое время. Это означает, что каждый раз, когда вы нажимаете jButton1 до завершения кода, он добавляет новое событие в EventQueue. Поэтому, если вы повторно нажали jButton1, то в очередь будет добавлено больше событий. Вы не могли переполнить его таким образом, потому что вы не могли нажимать достаточно быстро и достаточно долго, не сдаваясь. Но если и событие, такое как движение мыши, которое происходит на каждом пикселе, приводит к тяжелому событию. Тогда это может вызвать огромную очередь EventQueue, и это может привести к переполнению EventQueue. Способ устранения этой проблемы может состоять в том, чтобы запустить другой поток, как только произойдет событие. Например:

final Runnable r = new Runnable() { 
    public void run() { 
     try { 
      BufferedReader in = new BufferedReader(new FileReader("foo.txt")); 
      StringBuffer sb = new StringBuffer(); 
      char[] buf = new char[4096]; 
      int n; 
      while (-1 != (n = in.read(buf))) { 
       sb.append(buf, 0, n); 
      } 
      in.close(); 
      final String s = sb.toString(); 
      EventQueue.invokeLater(new Runnable(){ 
       public void run(){ 
        jTextPane1.setText(s); 
       } 
      }); 
     } catch (IOException ioe) { 
      ioe.printStackTrace(); 
     } 
    } 
}; 
ActionListener l = new ActionListener(){ 
    public void actionPerformed(ActionEvent ae){ 
     new Thread(r).start(); 
    } 
}; 
jButton1.addActionListener(l); 

Причина, по которой необходимо будет ссылаться на что-то на резьбе EventQueue, например, в

EventQueue.invokeLater(new Runnable(){ 
    public void run(){ 
     jTextPane1.setText(s); 
    } 
}); 

Это потому, что в противном случае экран не будет обновляться. Например, если поддерживать индикатор выполнения, EventQueue.invokeLater() будет обновлять экран СЕЙЧАС, но если он не завернут в EventQueue.invokeLater(), он будет ждать завершения потока, прежде чем он обновит экран. Это бесполезно, когда дело доходит до баров прогресса. В этом случае это, вероятно, мало что делало.

Thanx для отличного вопроса!

+0

Спасибо за ответ! Вы очень основательны. Мой вопрос касался Java ME, а не Java SE. Однако идея с «EventQueue» выглядит как одна и та же. К сожалению, ответ по-прежнему не устраняет мою текущую проблему ** J2ME **. Я возьму то, что вы сказали, и попытается исправить это сам. –

+0

Ну, это был тупик, даже если NetBeans не смог его найти. –

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