SwingWorker
アプリケーション内にクラスを実装しようとしています。SwingWorkerが「タイムアウト」するまでの時間を設定する方法はありますか?OutOfTime
キャッチして対処できる例外を投げるかもしれないと思っていました。どうやって実装すればいいのかわからない。
ご協力ありがとうございます!
SwingWorker
アプリケーション内にクラスを実装しようとしています。SwingWorkerが「タイムアウト」するまでの時間を設定する方法はありますか?OutOfTime
キャッチして対処できる例外を投げるかもしれないと思っていました。どうやって実装すればいいのかわからない。
ご協力ありがとうございます!
タスクをRunnableに埋め込んで、新しいシングルスレッドのExecutorServiceにドロップしてから、適切なタイムアウトでget()
結果のFutureに対してを実行してみませんか。get()
ジョブが時間内に完了しない場合は例外がスローされるため、タイムアウト機能が提供されます。
内部クラス MySwingWorker は、必要なことを十分に行うことができます。
package com.misc;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FutureStuffGUI extends JFrame {
/**
* Provides a variant of SwingWorker which operates with a timeout.
*
* @param <T>
*/
private static abstract class MySwingWorker<T> {
private T result;
private Exception raised;
/**
* Constructor.
*
* @param timeout
* @param timeUnit
*/
public MySwingWorker(final long timeout, final TimeUnit timeUnit) {
result = null;
raised = null;
System.out.println(Thread.currentThread().getName() + " starting");
final FutureTask<T> future = new FutureTask<T>(new Callable<T>() {
public T call() throws Exception {
System.out.println(Thread.currentThread().getName() + " running");
T result = doInBackground();
return result;
}
});
System.out.println(Thread.currentThread().getName() + " future: " + future);
final Thread runner = new Thread(null, future, "FutureThread");
Thread watcher = new Thread(null, new Runnable() {
@Override
public void run() {
runner.start();
try {
result = future.get(timeout, timeUnit);
} catch (Exception ex) {
raised = ex;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
assert SwingUtilities.isEventDispatchThread();
done();
}
});
}
}, "WatcherThread");
watcher.start();
}
/**
* Implement this method as the long-running background task.
*
* @return
* @throws Exception
*/
abstract protected T doInBackground() throws Exception;
/**
* This method is invoked from the UI Event Dispatch Thread on completion or timeout.
*/
abstract protected void done();
/**
* This method should be invoked by the implementation of done() to retrieve
* the result.
*
* @return
* @throws Exception
*/
protected T get() throws Exception {
assert SwingUtilities.isEventDispatchThread();
if (raised != null) {
throw raised;
} else {
return result;
}
}
}
public FutureStuffGUI() {
super("Hello");
init_components();
}
private void init_components() {
JPanel panel = new JPanel();
JButton button = new JButton("Press");
panel.add(button);
add(panel);
pack();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new MySwingWorker<String>(5, TimeUnit.SECONDS) {
@Override
protected String doInBackground() throws InterruptedException {
assert !SwingUtilities.isEventDispatchThread();
System.out.println(Thread.currentThread().getName() + " doInBackground");
// if (true) { throw new RuntimeException("Blow up"); }
Thread.sleep(6 * 1000);
return "Hello world!";
}
@Override
protected void done() {
assert SwingUtilities.isEventDispatchThread();
String result;
try {
result = get();
System.out.println(Thread.currentThread().getName() + " done; result: " + result);
} catch (Exception ex) {
System.out.println(Thread.currentThread().getName() + " done; errored:");
ex.printStackTrace();
}
}
};
};
});
}
public static void main(String[] args) {
FutureStuffGUI ui = new FutureStuffGUI();
ui.setVisible(true);
}
}
短い答えは、要件によって異なりますが、「難しい」です。Java Concurrency In Practiceを読むことを強くお勧めします。
あなたができる基本的なことは、(a) SwingWorker の Runnable が割り込みに対応していることを確認し、(b) タイマーを設定する (または Brian が言及したブロッキング get() 呼び出しを使用する) ことです。
SwingWorker を使用しない特定の理由。get(long, java.util.concurrent.TimeUnit) ? アプリケーションで簡単に処理できる TimeoutException をスローします。