使用一个Java 8 Consumer作为Runnable Callback - 是线程安全的吗?

时间:2015-04-03 09:00:54

标签: java multithreading callback thread-safety java-8

我有一个ScheduledThreadPoolExecutor有4个活动线程。它充满了一堆任务,每个任务处理一大块物品。

每个任务必须有3个回调:每个已处理项目的开始,结束和一个。

每个回调都会在我的数据库中触发更新。这是一项长期运作的任务。


这是一段示例代码,应该说明我正在做的事情:

public static void main(String[] args) throws InterruptedException {
    ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(4);

    Consumer<String> processed = (String o) -> {
            System.err.println("PROCESSED: " + o);
            try { Thread.sleep(10); }
            catch (Exception e) { e.printStackTrace(); }
    };

    for(int i=0; i<10; i++) {
        executor.schedule(
                new ChunkTask("task"+i, processed),
                500,
                TimeUnit.MILLISECONDS
        );
    }

}


public static class ChunkTask implements Runnable {
    String taskId;
    Consumer<String> processedCallback;

    public ChunkTask(String taskId, Consumer<String> processedCallback) {
        this.taskId = taskId;
        this.processedCallback = processedCallback;
    }

    @Override
    public void run() {
        for(int i=0; i<50; i++) {
            processedCallback.accept(taskId+" "+i);
        }
    }
}

我只是省略了开始和结束回调,因为它与处理过的回调基本相同。


如您所见,我创建了一个Consumer对象。其中有一个Thread.sleep(10)来模拟数据库访问。所有4个线程并行调用此对象。

我想知道这是否是线程安全的。 在我看来Consumer只是一个无状态对象,使用无状态方法。虽然你可以多次同时调用它。

我是对的吗?


编辑:我知道我的回调是同步的。这仅用于测试。后来我想把它变成异步。

1 个答案:

答案 0 :(得分:2)

是的,您的消费者没有任何状态,因此它是线程安全的。它使用的唯一共享对象是System.err,它本身是线程安全的。

当然,在实际代码中,线程安全性取决于您的操作,而不是打印到System.err。如果您使用共享数据库服务并且此服务不是线程安全的,那么您将遇到问题。