2012-09-22 3 views
2

문제점 : 모든 작업자 스레드가 중지 된 후 주 응용 프로그램 창이 닫히기를 원합니다. 쉽습니다. 그러나 나는 또한 창을 닫음으로써 메시지가 보내지기 전에 SwingWorker가 보낸 메시지가 처리되도록하고 싶다. 여기에 (아주) 작은 예제 소스 파일이 있습니다.SwingWorker를 Swing과 어떻게 동기화합니까?

/***************************************************************************** 
    TestAsyncEvents.java 

This example shows that messages from SwingWorker threads get processed 
*AFTER* the WINDOW_CLOSED event even if they had been generated 
*BEFORE* them. 
The question is: HOW DO I MAKE IT RIGHT? 
I know the answer, but it doesn't satisfy me. ;) 
*****************************************************************************/ 
import java.util.List; 
import java.awt.Dimension; 
import java.awt.Toolkit; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

////////////////////////////////////////////////////////////////////////////// 
// 
public class TestAsyncEvents extends JFrame 
{ 

/* 
* This class is for closing main window 
*/ 
private class Closer extends WindowAdapter 
{ 
    @Override public void windowClosing(WindowEvent ev) { handleWindowClosing(); } 
    @Override public void windowClosed(WindowEvent ev) { handleWindowClosed(); } 
} 

/* 
* This class represents worker that gets asked to stop 
* and then reports when it actually stops 
*/ 
private class Ticker extends SwingWorker<Boolean,String> 
{ 
    private boolean stop_flag = false; 
    private int  counter = 0; 
    private boolean result; 
    Ticker() { super(); execute(); } 
    @Override protected Boolean doInBackground() 
    { 
     // body, executed in worker thread 
     try { 
      while(!stop_flag) 
      { 
       Thread.sleep(2000); 
       publish(String.format("Tick #%d",++counter)); 
      } 
      return result=true; 
     } catch(Exception ex) { 
      return result=false; 
     } 
    } 
    @Override protected void process(List<String> chunks) 
    { 
     // reports progress, executed in gui thread 
     for(String chunk: chunks) 
      System.out.println(String.format("Chunk processed: %s",chunk)); 
    } 
    @Override protected void done() 
    { 
     // reports result, executed in gui thread 
     System.out.println(String.format("Thread is %s.",isCancelled()?"cancelled":"stopped normally")); 
     System.out.println(String.format("Result is %s.",Boolean.toString(result))); 
     //postClosing(); // IT IS THE SOLUTION FOR MY PROBLEM! BUT... IT ISN'T GOOD ONE! 
    } 
    public void askToStop() { stop_flag = true; } 
} 

/****************************************************************************/ 
/* FIELDS                 */ 
/****************************************************************************/ 
private static TestAsyncEvents  self; 
private Ticker  worker_object = null; 

/****************************************************************************/ 
/* CONSTRUCTOR                */ 
/****************************************************************************/ 
TestAsyncEvents() 
{ 
    super("Testing Async Events"); 
    addWindowListener(new Closer()); 
    setMinimumSize(new Dimension(512,384)); 
    setVisible(true); 
    worker_object = new Ticker(); 
} 

/****************************************************************************/ 
/* INNER METHODS               */ 
/****************************************************************************/ 
/* 
* Waiting for worker to finish 
*/ 
private void doStopping() 
{ 
    worker_object.askToStop(); 
    while(!worker_object.isDone()); 
} 
private boolean stopInSeparateThread() 
{ 
    try { 
     Thread closer = new Thread(new Runnable(){public void run(){doStopping();}}); 
     closer.start(); 
     closer.join(); 
     return true; 
    } catch(Exception ex) { 
     return false; 
    } 
} 
private boolean stopHere() 
{ 
    doStopping(); 
    return true; 
} 
private boolean stopWorker() 
{ 
    //return stopInSeparateThread(); 
    return stopHere(); 
} 
private boolean canClose() 
{ 
    return worker_object.isDone(); 
} 
/* 
* Posting WM_CLOSE events 
*/ 
private void doPostCloseEvent() 
{ 
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new WindowEvent(this,WindowEvent.WINDOW_CLOSING)); 
} 
private void postInSeparateThread() 
{ 
    SwingUtilities.invokeLater(new Runnable(){public void run(){doPostCloseEvent();}}); 
} 
private void postHere() 
{ 
    doPostCloseEvent(); 
} 
private void postClosing() 
{ 
    //postInSeparateThread(); 
    postHere(); 
} 
/* 
* Methods for Closer class 
*/ 
private void handleWindowClosing() 
{ 
    System.out.println("Closing main window..."); 
    if(canClose()) 
    { 
     System.out.println("Can close! Disposing..."); 
     dispose(); 
    } else { 
     System.out.println("Can't close! Now we'll allow it by stopping worker thread..."); 
     boolean res = stopWorker(); 
     System.out.println(String.format("Stopping worker thread went %s.",res?"okay":"wrong")); 
     postClosing(); // HERE I SIGNAL THE MAIN WINDOW TO CLOSE 
    } 
} 
private void handleWindowClosed() 
{ 
    System.out.println("Main window is closed!"); 
} 

/****************************************************************************/ 
/* ENTRY POINT                */ 
/****************************************************************************/ 
public static void main(final String[] args) 
{ 
    SwingUtilities.invokeLater(new Runnable(){public void run(){self=new TestAsyncEvents();}}); 
    System.out.println("All systems are go!"); 
} 

} 
////////////////////////////////////////////////////////////////////////////// 

그것의 출력은 여기에 있습니다 :하지

F:\C\Java\Test-Frame-Events>java TestAsyncEvents 
All systems are go! 
Chunk processed: Tick #1 
Closing main window... 
Can't close! Now we'll allow it by stopping worker thread... 
Stopping worker thread went okay. 
Chunk processed: Tick #2 
Thread is stopped normally. 
Result is true. 
Closing main window... 
Can close! Disposing... 
Main window is closed! 

SwingWorker의에서 이벤트가 완전히 다른 이벤트 큐에 처리하는 것을 나에게 발생 : 내가 원하는 것은 여기

F:\C\Java\Test-Frame-Events>java TestAsyncEvents 
All systems are go! 
Chunk processed: Tick #1 
Closing main window... 
Can't close! Now we'll allow it by stopping worker thread... 
Stopping worker thread went okay. 
Closing main window... 
Can close! Disposing... 
Main window is closed! 
Chunk processed: Tick #2 
Thread is stopped normally. 
Result is true. 

창 메시지 등을 처리하는 서버. 작업자 스레드가 WINDOW_CLOSING 이벤트를 게시하기 전에 모든 메시지를 중지하고 게시하기 위해 의도적으로 기다립니다. 그러나 그것은 도움이되지 않습니다 - SwingWorker의 메시지는 WINDOW_CLOSING 및 WINDOW_CLOSED 이벤트 후에도 계속 처리됩니다. 이것은 수많은 작은 불편을 낳습니다. 특히, WINDOW_CLOSED 핸들러의 모든 로그를 닫을 때, 내 프로그램에서 마지막으로 실행 된 연산자가되기를 희망하면서, 작업자 스레드의 모든 메시지는 시간과 공간에서 손실됩니다.

내 문제에 대한 해결책을 알고 있습니다. 나는 라인 # 68과 코멘트 라인 # 161의 주석을 풀어 줘야한다. 그러나 두 개 이상의 SwingWorker 스레드가있는 경우 모든 작업자를 조사하는 다른 스레드를 생성하고 모든 스레드가 중지되면 종료하도록 주 창에 신호를 보내야 함을 의미합니다. 그리고 그것은 단순하지 않습니다, IMHO. 자바 전문가입니다. 어떻게 해결할 수 있겠습니까?

답변

2

한 가지 가능한 해결 방법 : PropertyChangeListener를 사용하는 것이 좋습니다 : 여러 직원이있는 경우

private void handleWindowClosing() { 
    System.out.println("Closing main window..."); 
    if (canClose()) { 
    System.out.println("Can close! Disposing..."); 
    dispose(); 
    } else { 
    System.out 
      .println("Can't close! Now we'll allow it by stopping worker thread..."); 

    worker_object.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (SwingWorker.StateValue.DONE.equals(pcEvt.getNewValue())) { 
       postClosing(); 
      } 
     } 
    }); 


    boolean res = stopWorker(); 
    System.out.println(String.format("Stopping worker thread went %s.", 
      res ? "okay" : "wrong")); // !! 
    // postClosing(); // HERE I SIGNAL THE MAIN WINDOW TO CLOSE 
    } 
} 

, 당신은 아마도 CountDownLatch를 사용하거나 수를 CyclicBarrier

+1

참고 사항이 관련 [예] (HTTP : // 유래 .com/a/11372932/230513). – trashgod

+0

감사합니다. 나는 이것들을 시도하고 가장 잘 작동하는 것을 보게 될 것입니다. –

관련 문제