문제

스윙 애플리케이션을 만들었지 만 다음과 같은 문제가 있습니다.

이벤트 디스패치 스레드에서 "Thread-Main"이라는 Swingworker 스레드를 시작했으며 GUI의 Jlabel 참조를 "스레드 메인"으로 전달했습니다.

이제 "스레드 메인"에서 10 개의 스레드를 시작했습니다.

이제 10 개의 스레드가 모두 jlabel을 업데이트해야합니다.

어떻게 할 수 있습니까?

누군가 스윙 워크 사람의 10 스레드 하위 클래스를 먼저 만들고 게시 ( "") 메소드를 호출하고 그 "게시"메소드에서 문자열을 전달한 다음 다음 메소드로 게시 된 모든 문자열을 수집 하여이 작업을 수행 할 수 있다고 말했습니다. "스레드 메인"

@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. 위의 접근법이 그렇게하는 것이 맞습니까?
  2. 10 개의 스레드가 스윙 워크의 서브 클래스 여야합니까?
  3. 그렇게 할 다른 방법이 있습니까?
도움이 되었습니까?

해결책

  1. 아니 - 이것은 잘못된 접근법입니다 스레드 수를 제어하려면 당신 자신. 왜요? 당신이 보면 SwingWorker 코드는 그것이 a를 사용한다는 것을 알 수 있습니다 ThreadPoolExecutor 내부적으로 최대 10 개의 스레드를 포함합니다. 당신이 여러 가지를 시작하면 SwingWorker동시에 그들은 모두이 집행자를 사용하여 달릴 것입니다. 하지만, 배경 스레드가 병렬로 실행되는지에 대한 직접적인 제어가 없습니다..
  2. 지점 1을 참조하십시오.
  3. 권장 솔루션은 다음과 같습니다.

    • 싱글을 만듭니다 SwingWorker.
    • doInBackground() 메소드는 직접 또는 사용하여 10 스레드를 시작합니다. ExecutorService.
    • a CountDownLatch 또는 CompletionService 마스터 스레드 사이를 동기화하려면 (즉 SwingWorker 배경 스레드) 및 작업자 실.

예시

호출 할 작업자 스레드 수를 정의하고 업데이트 할 jlabel을 선언합니다.

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

우리가 실행하려는 작업 단위를 Callable<String>. 그만큼 String 결과를 업데이트하는 데 사용됩니다 JLabel.

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

이제 시작 a SwingWorker, 이로 인해 여러 병렬 작업자가 꺼져 모든 처리를 수행 할 것입니다. 근로자는 전화를 통해 결과를 반환하지 않습니다. done() (따라서 Void 유형) 그러나 ~ 할 것이다 마샬 중간체 String 호출하여 스윙 스레드에 다시 결과를 얻습니다 process(String... chunks).

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

정의하다 doInBackground() 작업자 스레드를 시작하고 각 결과를 사용하여 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);
  }
}

이제 우리는 구현합니다 process(String... chunks) 간단히 업데이트하려면 JLabel 전화 할 때.

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

마침내 우리는 무시합니다 done() 스윙 스레드에 대한 예외를 마샬링합니다.

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

다른 팁

어쩌면 더 쉬운 접근 방식은 SwingUtilities.invokelater (...) 메소드에서 GUI를 업데이트하는 코드를 래핑하는 것일 수 있습니다.

편집 : 라벨을 업데이트 할 때마다 개별 스레드에서 다음과 같습니다.

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

왜 10 개의 스레드가 필요한가요? 하나의 추가 스레드가하지 않는 이유는 무엇입니까?

실제 질문 : 해결하려는 문제는 무엇입니까?

직접 질문에 답하기 위해 :

1) 예, 올바른 접근법입니다.

3) EDT에서 별도의 스레드를 원한다면; 그런 다음 SwingWorker를 사용해야합니다. 그래서 그것은입니다 방법 그것을하기 위해.

행운을 빕니다!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top