プログラマメモ2 - programmer no memo2

swingを使って画面から、スレッドを起動して、終了したら、画面で値を表示といった使い方を想定しています。 2014/06/21

Javaです。concurrentです。
swingを使って画面から、スレッドを起動して、終了したら、画面で値を表示といった使い方を想定しています。
SwingWorkerから、ExecutorServiceを使うというようなことを試してみました。

あと、スレッドもひとつではなく複数を想定しています。
ためしたコードでは、3つです。

参考
ExecutorService での処理のキャンセル方法 - Java 入門

今回いろいろ試してみました。
CountDownLatch
ExecutorService
FutureTask


package concurrent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class TestMain4 { public static void main(String[] args) throws InterruptedException { a(); } public static class Dummy { public void open() { }; public void close() { }; } public static class MySwingWorker extends SwingWorker<Object, Object> { final int numThread = 3; // 明示的な shutdown が行われるまでは、スレッドはプール内に存在します。 ExecutorService executor = Executors.newFixedThreadPool(numThread); CountDownLatch countDownLatch = new CountDownLatch(numThread); final List<FutureTask<String>> list = new ArrayList<>(); @Override protected Object doInBackground() throws Exception { // 実行するタスクを作成 for (int i = 0; i < numThread; i++) { list.add(new FutureTask<>( new MyCallable("" + i, countDownLatch), "" + i)); } // タスクの実行 for (FutureTask<String> ft : list) { executor.submit(ft); } System.out.println("*** 1 this line" + new Date()); // 以前に送信されたタスクが実行されますが、新規タスクは受け入れられません。 executor.shutdown(); System.out.println("*** 2 this line" + new Date()); // 待ち countDownLatch.await(); return "OK"; } /** * この実装はよいのか? */ public void cancel() { super.cancel(true); // 後処理 executor.shutdownNow(); for (FutureTask<String> task : list) { // 全てのタスクにキャンセルを投げる // スレッドが停止? task.cancel(true); } } } static class MyCallable implements Runnable { String name; CountDownLatch countDownLatch; public MyCallable(String name, CountDownLatch countDownLatch) { this.name = name; this.countDownLatch = countDownLatch; } @Override public void run() { Dummy dummy = null; try { dummy = new Dummy(); dummy.open(); System.out.printf("*** start %s %s %n", name, new Date()); /* ループ処理をイメージ */ for (int i = 0; i < 1; i++) { for (int j = 0; j < 1000000000; j++) { // キャンセルされた場合よばれるはず... if (Thread.interrupted()) { throw new InterruptedException("!!cancelled!!"); } } } System.out.println("*** 計算終了"); } catch (Exception e) { // e.printStackTrace(); // キャンセルするとここを通る System.err.println(e.getLocalizedMessage()); } finally { // 後処理 if (dummy != null) dummy.close(); // 必ず呼ばれて欲しい countDownLatch.countDown(); System.out.printf("*** end %s %s %n", name, new Date()); } } } static void a() throws InterruptedException { final MySwingWorker worker = new MySwingWorker(); worker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { System.out.println(evt); if (!SwingWorker.StateValue.DONE.equals(worker.getState())) return; for (FutureTask<String> task : worker.list) { try { if (task.isDone() && !task.isCancelled()) System.out.println("result:" + task.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } }); SwingUtilities.invokeLater(worker); Thread.sleep(10); // キャンセルする場合は // worker.cancel(); } }

: