Frage

Ich habe eine Schaukel Anwendung gemacht, aber es gibt ein Problem, dass die wie folgt lautet:

Ich habe einen Thread Swingworker namens "Thread-Main" aus dem Event Dispatch Thread gestartet und habe eine JLabel Referenz der GUI zum "Thread-Main" übergeben.

Jetzt habe ich 10 Fäden von dem "Thread-Main" gestartet.

Jetzt möchte ich, dass alle 10 Threads den JLabel aktualisieren sollte.

Wie kann ich das tun?

Jemand hat mir gesagt, dass ich das tun kann, indem zuerst die alle machen 10 Fäden Subklassen von Swingworker und dann ruft die ( „“) veröffentlichen Methode und die Zeichenfolge in diesem passing „veröffentlichen“ -Methode und dann alle veröffentlichten Saiten durch das Sammeln von folgende Verfahren in "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. Ist der obige Ansatz ist richtig, dass zu tun?
  2. Sollten die 10 Threads Subklassen von Swingworker sein?
  3. Gibt es eine andere Möglichkeit, das zu tun?
War es hilfreich?

Lösung

  1. Nein - Dies ist der falsche Ansatz , wenn Sie die Anzahl der Threads selbst steuern möchten. Warum? Denn wenn man an der SwingWorker Code sehen Sie werden sehen, dass es eine ThreadPoolExecutor intern verwendet maximal 10 Threads enthält. Wenn Sie eine Reihe von SwingWorker des Kick-off gleichzeitig werden sie alle laufen diese Vollstrecker mit. Allerdings Sie haben keine direkte Kontrolle darüber, ob die Hintergrund-Threads ausgeführt werden parallel .
  2. Siehe Punkt 1.
  3. Meine empfohlene Lösung wäre:

    • Erstellen Sie eine einzelne SwingWorker.
    • Im doInBackground() Methode 10 Fäden kick off entweder direkt oder durch eine ExecutorService verwenden.
    • Verwenden eines CountDownLatch oder CompletionService zwischen dem Master-Faden (d.h. SwingWorker Hintergrund-Thread) und Arbeiter-Threads zu synchronisieren.

Beispiel:

Definieren Sie die Anzahl der Worker-Threads aufrufen und erklären die JLabel aktualisiert werden.

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

Definieren Sie die Einheit der Arbeit wollen wir als Callable<String> auszuführen. Das String Ergebnis verwendet wird, um die JLabel zu aktualisieren.

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

Jetzt ein SwingWorker kick off, was wiederum mehrere parallele Arbeiter beginnen jede Verarbeitung zu tun. Der Arbeiter wird kein Ergebnis über den Anruf zurück zur done() (daher der Void Typ), aber marshall Zwischen String Ergebnissen zurück auf den Swing-Thread von process(String... chunks) aufrufen.

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

definieren doInBackground(), um die Arbeitsthreads und Block für jedes Ergebnis mit einem CompletionService zu beginnen.

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

Jetzt implementieren wir process(String... chunks) einfach die JLabel zu aktualisieren, wenn genannt.

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

Schließlich außer Kraft setzen wir done() zu marshall zurück Ausnahmen auf den Swing-Thread.

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.
  }
}

Andere Tipps

Vielleicht ein einfacher Ansatz ist, um den Code zu wickeln, das das GUI in einer SwingUtilities.invokeLater (...) Methode aktualisiert.

Edit: In Ihrem einzelnen Threads, wenn Sie das Etikett aktualisieren möchten Sie tun:

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

Warum brauchen Sie 10 Threads? warum nicht ein extra Thread tun?

Die eigentliche Frage: Was ist das Problem, das Sie versuchen zu lösen

?

Ihre direkten Fragen zu beantworten:

1) ja, das ist der richtige Ansatz 2) ja, sollten die Fäden sein SwingWorkers (wenn Sie NetBeans verwenden, können Sie auch Aufgaben verwenden, die Subklassen von Swingworker auch)

sind

3), wenn Sie einen separaten Thread aus dem edt haben wollen; dann müssen Sie einen Swingworker verwenden; so dass der Weg , es zu tun.

viel Glück!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top