java并发包中是否有任何执行器可以保证所有任务都按照提交的顺序完成?

时间:2012-02-23 09:39:09

标签: java concurrency producer-consumer executorservice

从标题中演示该想法的代码示例:

executor.submit(runnable1);
executor.submit(runnable2);

我需要确保runnable1将在runnable2启动之前完成,而我在执行程序文档中没有找到任何此类行为的证据。

关于我正在解决的问题: 我需要在文件中写入大量日志。每个日志都需要大量预先计算(格式化和其他一些东西)。所以,我想将每个日志记录任务放到一种队列中,并在一个单独的线程中处理这些任务。当然,保持日志订购非常重要。

3 个答案:

答案 0 :(得分:4)

单线程执行程序将按提交的顺序执行所有任务。如果您希望同时执行任务,则只能使用具有多个线程的线程池。

将任务添加到队列本身可能很昂贵。您可以使用像这样的交换器

http://vanillajava.blogspot.com/2011/09/exchange-and-gc-less-java.html?z#!/2011/09/exchange-and-gc-less-java.html

这可以避免使用队列或创建对象。

更快的替代方法是使用不需要后台线程的内存映射文件(实际上操作系统在后台工作)这再次快得多。它支持亚微秒延迟和每秒数百万条消息。

https://github.com/peter-lawrey/Java-Chronicle

答案 1 :(得分:0)

您可以创建一个类似下面的简单包装器,以便所有Runnables在同一个线程中执行(即按顺序执行),然后将该包装器提交给执行程序。这并不能解决日志记录问题。

class MyRunnable implements Runnable {

    private List<Runnable> runnables = new ArrayList<>();

    public void add(Runnable r) {
        runnables.add(r);
    }
    @Override
    public void run() {
        for (Runnable r : runnables) {
            r.run();
        }
    }

}

//......
MyRunnable r = new MyRunnable();
r.add(runnable1);
r.add(runnable2);
executor.submit(r);    

答案 2 :(得分:0)

据推测,您正在对日志文件进行一些后期分析?您是否考虑过不关心他们写的订单以及稍后离线重新订购。您可以在提交时使用时间戳或AtomicLong分配唯一ID吗?

代码草图(未经测试)看起来像这样:

import java.util.concurrent.atomic.AtomicLong;

class MyProcessor {

    public void work()
        for (Object data: allData) {
            executor.submit(new MySequencedRunnable(data);
        }
    }

}

class MySequencedRunnable implements Runnable {
    private static final AtomicLong LOG_SEQUENCE_ID = new AtomicLong(0);

    private final Object data;

    MySequencedRunnable(Object data) {
       this.data = data;

    }

    public void run() {
        LOGGER.log(LOG_SEQUENCE_ID.incrementAndGet(), data);
    }

}

另外请考虑,如果您使用的是log4j,请使用NDCMDC来协助重新排序。