ThreadPoolExecutor线程安全吗?

ExecutorService保证线程安全吗?

我将从不同的线程提交工作到同一个ThreadPoolExecutor,我必须在交互/提交任务之前同步访问执行器吗?

确实,JDK类似乎没有明确保证线程安全的任务提交。 但是,实际上,库中的所有ExecutorService实现确实是线程安全的。 我认为这是合理的。 由于所有实现这些function的代码都被放置在公共领域,所以任何人都不可能以完全不同的方式重写它。

(与其他答案相反)线程安全契约logging:查看interface javadocs(而不是javadoc的方法)。 例如,在ExecutorService javadoc的底部find:

内存一致性效果:在将一个Runnable或Callable任务提交给一个ExecutorService之前,一个线程中的动作发生在该任务采取的任何动作之前 ,这反过来发生 – 在通过Future.get()获取结果之前

这足以回答这个问题:

“在交互/提交任务之前,我必须同步执行者的访问吗?

不,你不知道。 构build任何(正确实现的) ExecutorService而无需外部同步就可以了。 这是主要的devise目标之一。

ExecutorService是一个并发实用程序,也就是说它被devise为最大程度地运行而不需要同步性能。 (同步会导致线程争用,这会降低multithreading效率 – 特别是在扩展到大量线程时。)

不能保证任务在将来什么时间执行或完成(有些甚至可以在提交它们的同一个线程上立即执行),但工作线程保证已经看到了提交线程执行的所有效果提交点 。 因此(运行的线程)你的任务也可以安全地读取为它的使用而创build的任何数据,而不用同步,线程安全的类或任何其他forms的“安全发布”。 提交任务的行为本身就足以“安全地”将input数据发布给任务。 您只需要确保input数据在任务运行时不会以任何方式进行修改。

同样,当你通过Future.get()取回任务的结果时,检索线程将保证看到执行者的工作线程所做的所有效果(在返回的结果中,加上任何副作用都改变了worker-线程可能已经)。

这个合同也意味着任务本身可以提交更多的任务。

“ExecutorService保证线程安全吗?

现在这个问题的这个部分更一般化了。 例如找不到关于方法shutdownAndAwaitTermination的线程安全合同的任何声明 – 尽pipe我注意到Javadoc中的代码示例没有使用同步。 (虽然也许有一个隐藏的假设,closures是由创build执行程序的同一个线程,而不是例如一个工作线程煽动?)

顺便说一下,我会推荐一本关于并发编程世界的好地球“Java并发实践”一书。

你的问题是相当开放的:所有的ExecutorService接口都是保证某个线程在某个地方处理提交的Runnable或者Callable实例。

如果提交的Runnable / Callable引用了可从其他Runnable / Callable实例访问的共享数据结构(可能由不同线程同时处理),那么确保跨该数据结构的线程安全是您的责任

要回答你的问题的第二部分,是的你可以在提交任何任务之前访问ThreadPoolExecutor; 例如

 BlockingQueue<Runnable> workQ = new LinkedBlockingQueue<Runnable>(); ExecutorService execService = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.SECONDS, workQ); ... execService.submit(new Callable(...)); 

编辑

基于布赖恩的评论,以防万一我误解了你的问题:从多个生产者线程提交到ExecutorService的任务通常是线程安全的(尽pipe没有在接口的API中明确提到,据我所知)。 任何不提供线程安全的实现在multithreading环境中都是没用的(因为多个生产者/多个消费者是一个相当常见的范例),这就是ExecutorService (和其余的java.util.concurrent )为…devise。

对于ThreadPoolExecutor ,答案是简单的。 ExecutorService不会强制或保证所有的实现都是线程安全的,而且它不能作为接口。 这些types的合约超出了Java界面的范围。 但是, ThreadPoolExecutor都是和明确logging为线程安全的。 此外, ThreadPoolExecutor使用java.util.concurrent.BlockingQueuepipe理它的作业队列,它是一个请求所有实现都是线程安全的接口。 任何BlockingQueue java.util.concurrent.*实现都可以安全地假定为线程安全的。 任何非标准的实现都不可能,尽pipe如果有人提供了一个BlockingQueue实现队列,而这个实现队列不是线程安全的,那将是非常愚蠢的。

所以你的标题问题的答案显然是肯定的 。 对于你的问题的后面的答案可能是 ,因为两者之间有一些差异。

与Luke Usherwood声称的答案相反,文档并不暗示ExecutorService实现保证是线程安全的。 至于ThreadPoolExecutor的问题,请参阅其他答案。

是的,指定了before-before关系,但这并不意味着方法本身的线程安全性,正如Miles所评论的。 在卢克·厄舍伍德的回答中,指出前者足以certificate后者,但没有提出实际的论点。

“线程安全”可能意味着各种各样的事情,但这里是Executor (不是ExecutorService但没有区别)的一个简单的反例,它平凡地满足所需的发生之前的关系,但是由于非同步访问而不是线程安全的count字段。

 class CountingDirectExecutor implements Executor { private int count = 0; public int getExecutedTaskCount() { return count; } public void execute(Runnable command) { command.run(); } } 

免责声明:我不是专家,我发现这个问题,因为我自己寻找答案。