java - 在 Java 中使用线程时维护 FIFO

标签 java multithreading concurrency parallel-processing

我正在尝试对按顺序接收的元素执行一项昂贵且可变长度的任务。必须保持元素顺序,同时仍然快速处理每个元素。

下面是一个 SSCWE(W 表示错误!),是我对并行处理的尝试。有没有办法确保每次调用 processSomething() 都在自己的线程中执行,同时在查看 ExecutorCompletionService 时仍保持 FIFO?

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadingHelper {

public static void main(String[] args) {

    ExecutorService pool = Executors.newFixedThreadPool(20);
    ExecutorCompletionService<String> compService 
        = new ExecutorCompletionService<String>(pool);

    // process some data
    processSomething(compService, "1.");
    processSomething(compService, "2..");
    processSomething(compService, "3...");
    processSomething(compService, "4....");
    processSomething(compService, "5.....");

    // print out the processed data
    try {
        System.out.println(compService.take().get());
        System.out.println(compService.take().get());
        System.out.println(compService.take().get());
        System.out.println(compService.take().get());
        System.out.println(compService.take().get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }

}

public static synchronized void processSomething(
        CompletionService<String> compService, final String x) {
    Callable<String> c = new Callable<String>() {

        @Override
        public String call() throws Exception {
            // this represents the variable and expensive 
                            // amount of time it takes to process x
            long rand = (long) (Math.random() * 100);
            Thread.sleep(rand);

            // this represents the processing of x
            String xProcessed = x.replace(".", "!");

            return xProcessed;
        }
    };
    compService.submit(c);
}
}

典型输出为

4!!!!
2!!
1!
5!!!!!
3!!!

但我想要

1!
2!!
3!!!
4!!!!
5!!!!!

最佳答案

使用Futures而不是CompletionService来按特定顺序获取结果,并且仍然受益于并行执行:

ExecutorService pool = Executors.newFixedThreadPool(20);
List<Future<String>> futures = new ArrayList<>();
futures.add(pool.submit(makeCallable("1.")));
// ...
for (Future<String> future : futures) {
    try {
        System.out.println(future.get());
    } catch (...) {
        ...
    }
}

public static Callable<String> makeCallable(String x) {
    Callable<String> c = ...;
    return c;
}

关于java - 在 Java 中使用线程时维护 FIFO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22923492/

相关文章:

java - 如何扩展由另一个类实例化的 java 类?

java - lock() 方法中的 Grails StaleObjectStateException

java - 多个线程共享/访问相同数据的问题

java - java中如何在一个线程完成时结束其他线程的处理

通过 != null 或 !str.equals(null) 检查 Java 字符串空值?

java - 由于容器启动的 AM 容器异常, headless (headless)环境中的 MapReduce 作业失败 N 次

java - 如何维护 Activity 线程的数量 - java

java - jSoup.connect(url).get() 给出错误异常 Android 应用程序

java - Java中同步方法的死锁

java - 如何从 txt 制作 Java Anagrams