0

最初に ProgressMonitor を定義します。

progressMonitor = new ProgressMonitor(parent, "Starting processing ...", "", 0, maxNumberProcesses+1);
progressMonitor.setProgress(0);

同じスレッドで ExecutorService と invokeAll() を使用して Callable のリストを処理します。

ExecutorService execService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // use all available processors at startup
execService.invokeAll(callables); // wait for all tasks to complete
execService.shutdownNow(); // free thread pool resources

各 Callable の形式は次のとおりです。

class Callable implements Callable<List<String>>
{
    public List<String> call()
    {
        List<String> files = doSomeStuff();
        progressBarUpdate();
        return files;
    }
}

すなわち; 各 Callable は、progressBarUpdate() を呼び出します。

private void progressBarUpdate()
{
    if (progressMonitor != null)
    {
        Lock lock = new ReentrantLock();
        lock.lock();
        try
        {
            progressMonitor.increment();
        }
        finally
        {
            lock.unlock(); // release lock
        }
    }
}

各 doSomeStuff() には独自の例外処理があり、エラーが発生するか例外がスローされると、null 値が返されます。これが、戻り値の型がリストであり、そのような場合は null を返す理由です。Callable とそれらが返すファイルのリストの間にクロスオーバーはありません。それらはすべて独自のファイルのリストを維持します。

正常に動作することがわかりましたが、次の形式の InterruptedException がスローされることがあります。

Disposal was interrupted:
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at java.awt.EventQueue.invokeAndWait(EventQueue.java:1263)
at java.awt.Window.doDispose(Window.java:1209)
at java.awt.Dialog.doDispose(Dialog.java:1196)
at java.awt.Window.dispose(Window.java:1147)
at javax.swing.ProgressMonitor.close(ProgressMonitor.java:311)
at javax.swing.ProgressMonitor.setProgress(ProgressMonitor.java:264)

モニターの最大値に達したときに setProgress() が close() を呼び出すことを示しています。

public void setProgress(int nv) {
    if (nv >= max) {
        close();
    }
...

そして close() には、他のスレッドセーフでない呼び出しが多数含まれています。

条件 nv>=max が満たされないようにコードを変更し、invokeAll() の後に明示的に ProgressMonitor.close() を呼び出しましたが、そのようなアプローチが完全にスレッドセーフであるとはまだ確信していません。

他の誰かがこの状況に遭遇し、堅実な解決策を見つけましたか?

ありがとう

グラハム

PS。ProgressMonitor は Swing ウィジェットではありませんが、Swing コンポーネントをカプセル化することに注意してください。その結果、ProgressMonitor が EDT で実行されないようにしました。

4

2 に答える 2

1

バックグラウンド タスクを実行して進行状況を表示する場合は、SwingWorkerを使用する必要があります。SwingWorkerにはprogressリッスンできるプロパティがあります。タスクがバックグラウンド スレッドで実行されている間に、進行状況の更新がイベント ディスパッチ スレッドで実行されるようにします。

例えば:

SwingWorker<?,?> task = ...;
final JProgressBar progressBar = new JProgressBar(0, 100);

task.addPropertyChangeListener(
        new PropertyChangeListener() {
            public  void propertyChange(PropertyChangeEvent evt) {
                 if ("progress".equals(evt.getPropertyName())) {
                     progressBar.setValue((Integer)evt.getNewValue());
            }
        }
 });

完全なサンプル コードは、SwingWorkerの javadoc にあります。

于 2013-12-24T10:38:33.480 に答える
0

これが原因のようですinterrupt

Worker Thread (Callable1):
close() -> doDispose() -> EventQueue.invokeAndWait() {
synchronized (lock) {
            Toolkit.getEventQueue().postEvent(event);
            lock.wait(); // --> (2) blocked window disposal event gets interrupted
        }
}

ExecutorService.shutdownNow() :
 try {
                for (Worker w : workers) {
                    w.interruptNow(); // (1) --> Setting interrupt flag
                }
            } catch (SecurityException se) { // Try to back out
                runState = state;
                // tryTerminate() here would be a no-op
                throw se;
            }

機能的には、progress-monitor が完了する (または に達するmax) と、イベントがディスパッチされる前 (eventQ のビジー状態に応じて発生する場合と発生しない場合があります) のように見えますが、サービス自体がシャットダウンします。

概念的には、コード内に特定の問題は見られませんが、主に実行者サービスによるAWT.EventQueue.

呼び出す前に消費するか使用することがInterruptedExceptionできprogressMonitor.increment();ます。ExecutorService.awaitTerminationshutdownNow

于 2013-12-24T10:38:55.837 に答える