2013-09-06 4 views
3

Интересно, как java SwingWorker и пул потоков работает, когда некоторая задача выполняется повторно. Вот SSCCE проблемы, готовой скопировать + паста:SwingWorker thread reusability

package com.cgi.havrlantr.swingworkerexample; 

    import java.awt.*; 
    import javax.swing.*; 

    public class Main extends JFrame { 

     public static void main(String[] args) { 
      java.awt.EventQueue.invokeLater(new Runnable() { 
       public void run() { 
        new Main().setVisible(true); 
       } 
      }); 
     } 

     public Main() { 
      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
      setSize(new Dimension(100,100)); 
      JButton btn = new JButton("Say Hello"); 
      add(btn); 
      btn.addActionListener(new java.awt.event.ActionListener() { 
       public void actionPerformed(java.awt.event.ActionEvent evt) { 
        btnPressed(evt); 
       } 
      }); 
     } 

     private void btnPressed(AWTEvent e) { 
      SayHelloSwingWorker worker = new SayHelloSwingWorker(); 
      worker.execute(); 
     } 

     private class SayHelloSwingWorker extends SwingWorker<Integer, Integer> { 

      protected Integer doInBackground() throws Exception { 
       System.out.println("Hello from thread " + Thread.currentThread().getName()); 
       return 0; 
      } 
     } 

    } 

Я хочу спросить о следующем. Каждый раз, когда я вызываю execute() в новом экземпляре рабочего (после нажатия кнопки), создается новый поток в пуле потоков SwingWorker до 10 созданных потоков. После превышения этого предела потоки повторно используются, как я ожидаю. Поскольку новые рабочие создаются последовательно после того, как предыдущий закончен, я не понимаю, почему первый поток не используется повторно, потому что предыдущий работник уже выполнил его работу. Скажем, может быть только один поток, который выполняет некоторые работы в то время. Я бы ожидал, что пул потоков создаст только один поток, который достаточно для выполнения всех задач. Это обычное поведение? Или может быть что-то неправильно, что отрицает повторное использование первого потока и заставляет поток пула создавать другой?

Если это нормально, я думаю, что это пустая трата времени для создания ненужной нити и памяти для поддержания готовности потоков. Можно мне это как-то избежать? Могу ли я заставить SwingWorker иметь только один поток в своем пуле? - Я думаю, нет, потому что количество потоков является постоянным и зависит от реализации Java, насколько я знаю.

Могу ли я заставить SwingWorker завершить поток после завершения задачи? (вызов this.cancel() в done() метод не работал)

Вот код моего реального рабочего мира, так как существует некоторая зависимость, которая может вызвать проблему.

public class MapWorker extends SwingWorker<Long, Object> { 
    @Override 
    protected Long doInBackground() throws Exception{ 
     try { 
       long requestId = handleAction(); 
       return requestId; 
    }catch(Exception e){ 
     logger.error("Exception when running map worker thread.", e); 
     SwingUtilities.invokeLater(new Runnable(){ 
      @Override 
      public void run(){ 
       requestFinished(); 
      } 
     }); 
     MapUtils.showFatalError(e); 
    } 

    return -1l; 
    } 

    @Override 
    protected void done(){ 
     try{ 
      requestId = get(); 
      logger.info("Returned from map request call, ID: {}", Long.toString(requestId)); 
     }catch(InterruptedException e){ 
      logger.error("Done interrupted - wierd!", e); 
     }catch(ExecutionException e){ 
      logger.error("Exception in execution of worker thread.", e); 
     } 
    } 

В методе handleAction() новый поток с некоторым блокирующим вызовом создается и идентификатор потока возвращается, что не должно быть ничего странно. Не спрашивайте меня, почему, это не мой код. :)

+1

для лучшей помощи скорее отправить сообщение SSCCE, – mKorbel

+0

[профиль] (http://stackoverflow.com/q/2064427/230513), чтобы проверить ожидания; нет необходимости в 'invokeLater()'; 'done()' работает на EDT. – trashgod

+0

и [я надеюсь, что не похоже на] (http://stackoverflow.com/q/14900697/714968) – mKorbel

ответ

3

Хммм ... по умолчанию ThreadPoolExecutor для SwingWorkers настроен не только на максимальный размер пула 10, но и на размер ядра 10, то есть он предпочитает сохранять 10 потоков в живых. Мне трудно объяснить, почему это так, может быть, это оптимально при определенных условиях.

Вы можете сказать SwingWorkers использовать пользовательский ExecutorService с помощью этого (странно) вызова:

AppContext.getAppContext().put(SwingWorker.class, Executors.newSingleThreadExecutor()); 

отметить, что установка ExecutorService возвращаемого Executors.newSingleThreadExecutor() будет создавать не-демон нить, что-то вы можете изменить.

+0

Кроме того, 'AppContext' имеет пакет' sun.awt', что означает, что вы должны быть очень осторожны при его использовании. Помимо этого, это единственное решение. –

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