在Java中使用线程时维护FIFO

时间:2014-04-07 21:30:10

标签: 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!!!!!

1 个答案:

答案 0 :(得分:2)

使用期货代替 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;
}