有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java主类在线程执行之前结束

我有一个多线程执行,我想跟踪并打印执行时间,但当我执行代码时,子线程比主执行时间长,因此输出不可见,也不会打印正确的值,因为它会提前终止

代码如下:

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(timeout, TimeUnit.SECONDS);

实际上,executor服务从不执行线程

哪种解决方案可以只在ExecutorService块中执行多线程,并在最后完成主执行


共 (2) 个答案

  1. # 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...
    
  2. # 2 楼答案

    考虑到您的用户情况,您最好使用invokeAll方法。从Javadoc:

    Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list. Note that a completed task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress.

    使用:

    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完成后检查收集的结果,以验证已完成任务的状态

    祝你好运