0

マルチスレッドの実行があり、実行時間を追跡して出力したいのですが、コードを実行すると、子スレッドはメインの実行よりも時間がかかるため、出力が表示されず、正しい値も出力されません。早期終了。

コードは次のとおりです。

public static void main(String[] args) throws CorruptIndexException, IOException, LangDetectException, InterruptedException {

    /* Initialization */
    long startingTime = System.currentTimeMillis();
    Indexer main = new Indexer(); // this class extends Thread
    File file = new File(SITES_PATH);
    main.addFiles(file);

    /* Multithreading through ExecutorService */
    ExecutorService es = Executors.newFixedThreadPool(4);
    for (File f : main.queue) {
        Indexer ind = new Indexer(main.writer, main.identificatore, f);
        ind.join();
        es.submit(ind);
    }

    es.shutdown();

    /* log creation - code I want to execute when all the threads execution ended */
    long executionTime = System.currentTimeMillis()-startingTime;
    long minutes = TimeUnit.MILLISECONDS.toMinutes(executionTime);
    long seconds = TimeUnit.MILLISECONDS.toSeconds(executionTime)%60;
    String fileSize = sizeConversion(FileUtils.sizeOf(file));

    Object[] array = {fileSize,minutes,seconds};
    logger.info("{} indexed in {} minutes and {} seconds.",array);
}

join()、wait()、notifyAll() などのいくつかのソリューションを試しましたが、どれも機能しませんでした。

私の問題を扱うstackoverflowでこのQ&Aを見つけましたが、join()は無視され、

es.awaitTermination(タイムアウト、TimeUnit.SECONDS);

実際、executor サービスはスレッドを実行しません。

ExecutorService ブロックでのみマルチスレッドを実行し、最後にメインの実行で終了するソリューションはどれですか?

4

2 に答える 2

1

ユーザーケースを考えると、このinvokeAll方法を利用することもできます。Javadoc から:

指定されたタスクを実行し、すべてが完了するとステータスと結果を保持する Future のリストを返します。Future.isDone() は、返されたリストの各要素に対して true です。完了したタスクは、通常どおり終了するか、例外をスローして終了する可能性があることに注意してください。この操作の進行中に指定されたコレクションが変更された場合、このメソッドの結果は未定義です。

使用するには:

final Collection<Indexer> tasks = new ArrayList<Indexer>();
for(final File f: main.queue) {
    tasks.add(new Indexer(main.writer, main.identificatore, f));
}

final ExecutorService es = Executors.newFixedThreadPool(4);
final List<Future<Object>> results = es.invokeAll(tasks);

これにより、提供されたすべてのタスクが実行され、処理が完了するのを待ってからメイン スレッドに進みます。特定のニーズに合わせてコードを微調整する必要がありますが、要点は理解できます。簡単なメモとして、invokeAllタイムアウト パラメータを受け入れるメソッドのバリアントがあります。続行する前に最大時間待機する場合は、そのバリアントを使用します。invokeAllまた、完了したタスクのステータスを確認するために、完了後に収集された結果を確認してください。

幸運を。

于 2012-04-18T00:41:03.873 に答える
1

このExecutorService#submit()メソッドはFuture、送信されたタスクが完了するまで待機するために使用できるオブジェクトを返します。

アイデアは、これらの をすべて収集してから、それぞれをFuture呼び出すget()というものです。これにより、サブミットされたすべてのタスクが完了してから、メイン スレッドが続行されます。

このようなもの:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Future<?>> futures = new ArrayList<Future<?>>();
for (File f : main.queue) {
    Indexer ind = new Indexer(main.writer, main.identificatore, f);
    ind.join();
    Future<?> future = es.submit(ind);
    futures.add(future);
}

// wait for all tasks to complete
for (Future<?> f : futures) {
    f.get();
}

// shutdown thread pool, carry on working in main thread...
于 2012-04-18T00:35:52.247 に答える