Pergunta

Eu fiz uma aplicação oscilações, mas há um problema no que é a seguinte:

I iniciaram um fio SwingWorker chamado "Thread-Main" a partir do Tópico Despacho Evento e passaram uma referência JLabel da GUI para o "Thread-Main".

Agora eu comecei 10 tópicos do "Thread-Main".

Agora, quero que todos os 10 threads deve atualizar o JLabel.

Como posso fazer isso?

Alguém me disse que eu posso fazer isso por primeira tomada de todas as 10 linhas subclasses de SwingWorker e, em seguida, chamar a publicar ( "") método e passando a cadeia em que "publicar" método e, em seguida, recolher todas as cordas publicados pela seguinte método em "thread-Main"

@Override
protected void process(List<String> labelStrings) {
    String count = labelStrings.get(labelStrings.size() - 1);
    label.setText(count); // label is a reference to a label in the GUI 
}
  1. É a abordagem acima é correto fazer isso?
  2. Caso os 10 threads ser subclasses de SwingWorker?
  3. Existe alguma outra maneira de fazer isso?
Foi útil?

Solução

  1. Não - Esta é a abordagem incorreta se você quiser controlar o número de threads si mesmo. Por quê? Porque se você olhar o código SwingWorker você verá que ele usa uma ThreadPoolExecutor contendo internamente um máximo de 10 linhas. Se você lançar uma série de SwingWorker é simultaneamente todos eles vão correr usando este executor. No entanto, você não tem controle direto sobre se os threads em segundo plano são executadas em paralelo .
  2. Ver ponto 1.
  3. A minha solução recomendada seria:

    • Criar um único SwingWorker.
    • No pontapé método doInBackground() off 10 threads diretamente ou por meio de um ExecutorService.
    • Use um CountDownLatch ou CompletionService a sincronizar entre o master thread (ou seja SwingWorker discussão de fundo) e segmentos de trabalho.

Exemplo

Defina o número de threads de trabalho para invocar e declarar o JLabel para ser atualizado.

final int nThreads = 10;
JLabel myLbl = new JLabel();

Defina a unidade de trabalho que deseja executar como um Callable<String>. O resultado String será usado para atualizar o JLabel.

private static class MyCallable implements Callable<String> {
  public String call() { ... }
}

Agora lançar uma SwingWorker, que por sua vez pontapé de saída vários trabalhadores paralelos para fazer qualquer processamento. O trabalhador não retornará um resultado via a chamada para done() (daí o tipo Void), mas marshall resultados String intermediário de volta para o segmento balanço chamando process(String... chunks).

new SwingWorker<Void, String>() {
  // See method definitions below.
}.execute();

Definir doInBackground() para lançar os threads de trabalho e de bloco para cada resultado utilizando uma CompletionService.

public Void doInBackground() throws Exception {
  // Define executor service containing exactly nThreads threads.
  ExecutorService execService = Executors.newFixedThreadPool(nThreads);


  // Define completion service that will contain the processing results.
  CompletionService compService = new ExecutorCompletionService(execService);    

  // Submit work to thread pool using the CompletionService.  Future<String>
  // instances will be added to the completion service's internal queue until complete.
  for (int i=0; i<nThreads; ++i) {
    compService.submit(new MyCallable());
  }

  // Take results from each worker as they appear and publish back to Swing thread.
  String result;
  while ((result = compService.take().get()) != null) {
    publish(result);
  }
}

Agora vamos implementar process(String... chunks) simplesmente atualizar o JLabel quando chamado.

public void process(String... chunks) {
  if (chunks.length > 0) {
    // Update label with last value in chunks in case multiple results arrive together.
    myLbl.setText(chunks[chunks.length - 1]);
  }
}

Finalmente, substituir done() para marshall quaisquer excepções de volta para o segmento Swing.

public void done() {
  try {
    get(); // Will return null (as per Void type) but will also propagate exceptions.
  } catch(Exception ex) {
    JOptionPane.show ... // Show error in dialog.
  }
}

Outras dicas

Talvez uma abordagem mais fácil é para embrulhar o código que atualiza a GUI em um método SwingUtilities.invokeLater (...).

Edit: Em seus segmentos individuais sempre que você deseja atualizar o rótulo você faz:

SwingUtilities.invokeLater(new Runnable()
{
    public void run()
    {
        label.setText(...);
    }
});

Por que você precisa de 10 tópicos? por um fio adicional não vai fazer?

a verdadeira questão: qual é o problema que você está tentando resolver

para responder às suas perguntas diretas:

1) Sim, essa é a abordagem correta 2) Sim, os fios devem ser SwingWorkers (se você estiver usando o NetBeans, você também pode usar Tarefas, que são subclasses de SwingWorker também)

3) se você quiser ter um segmento separado do BRT; então você precisa usar um SwingWorker; de modo que é a maneira para fazê-lo.

boa sorte!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top