문제점 : 모든 작업자 스레드가 중지 된 후 주 응용 프로그램 창이 닫히기를 원합니다. 쉽습니다. 그러나 나는 또한 창을 닫음으로써 메시지가 보내지기 전에 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. 자바 전문가입니다. 어떻게 해결할 수 있겠습니까?
참고 사항이 관련 [예] (HTTP : // 유래 .com/a/11372932/230513). – trashgod
감사합니다. 나는 이것들을 시도하고 가장 잘 작동하는 것을 보게 될 것입니다. –