ExecutorService抽象化了许多与低级抽象(如原始Thread)相关的复杂性,它提供了安全启动、关闭、提交、执行以及在任务成功或突然终止时阻塞的机制(表示为Runnable或Callable)。 从JCiP,第6.2节,直接从马的嘴: Executor可能是一个简单的接口,但它构成了支持各种任务执行策略的异步任务执行的灵活而强大的框架的基础。它提供了将task submission与task execution分离的标准方法,将任务描述为Runnable。Executor实现还提供了生命周期支持和挂钩,用于添加统计信息收集、应用程序管理和监控。... .Using anExecutoris usually the easiest path to implementing a producer-consumer design in your application. 而不是花时间实施(通常是错误的,而且需要付出很大的努力),j.u.concurrent框架允许您将重点放在构建任务、相关性和潜在的并行性上。对于大量的并发应用程序,可以直接识别和利用任务边界并利用j.u.c,从而使您能够专注于真正并发挑战的小得多的子集,这些挑战可能需要更专门的解决方案。 此外,尽管Oracle API page summarizing the concurrency utilities的外观和感觉都是样板文件,但它包含了一些使用它们的真正可靠的理由,尤其是: 开发人员可能已经了解了标准库类,因此无需学习特定并发组件的API和行为。此外,如果并发应用程序是基于可靠的、经过良好测试的组件构建的,则调试起来要简单得多。 Java concurrency in practice是一本关于并发性的好书。如果你还没有读过,那就去买一本吧。这里介绍的并发性的全面方法远远超出了这个问题,从长远来看,它会让你省去很多烦恼。
public class TaskOne implements Callable<String> {
@Override
public String call() throws Exception {
String message = "Task One here. . .";
return message;
}
}
public class TaskTwo implements Callable<String> {
@Override
public String call() throws Exception {
String message = "Task Two here . . . ";
return message;
}
}
// from the calling class
ExecutorService service = Executors.newFixedThreadPool(2);
// set of Callable types
Set<Callable<String>>callables = new HashSet<Callable<String>>();
// add tasks to Set
callables.add(new TaskOne());
callables.add(new TaskTwo());
// list of Future<String> types stores the result of invokeAll()
List<Future<String>>futures = service.invokeAll(callables);
// iterate through the list and print results from get();
for(Future<String>future : futures) {
System.out.println(future.get());
}
9条答案
按热度按时间2exbekwf1#
ExecutorService
抽象化了许多与低级抽象(如原始Thread
)相关的复杂性,它提供了安全启动、关闭、提交、执行以及在任务成功或突然终止时阻塞的机制(表示为Runnable
或Callable
)。从JCiP,第6.2节,直接从马的嘴:
Executor
可能是一个简单的接口,但它构成了支持各种任务执行策略的异步任务执行的灵活而强大的框架的基础。它提供了将task submission
与task execution
分离的标准方法,将任务描述为Runnable
。Executor
实现还提供了生命周期支持和挂钩,用于添加统计信息收集、应用程序管理和监控。... .Using an
Executoris usually the easiest path to implementing a producer-consumer design in your application.
而不是花时间实施(通常是错误的,而且需要付出很大的努力),
j.u.concurrent
框架允许您将重点放在构建任务、相关性和潜在的并行性上。对于大量的并发应用程序,可以直接识别和利用任务边界并利用j.u.c
,从而使您能够专注于真正并发挑战的小得多的子集,这些挑战可能需要更专门的解决方案。此外,尽管Oracle API page summarizing the concurrency utilities的外观和感觉都是样板文件,但它包含了一些使用它们的真正可靠的理由,尤其是:
开发人员可能已经了解了标准库类,因此无需学习特定并发组件的API和行为。此外,如果并发应用程序是基于可靠的、经过良好测试的组件构建的,则调试起来要简单得多。
Java concurrency in practice
是一本关于并发性的好书。如果你还没有读过,那就去买一本吧。这里介绍的并发性的全面方法远远超出了这个问题,从长远来看,它会让你省去很多烦恼。ruoxqz4g2#
我看到的一个优点是管理/调度多个线程。使用ExecutorService,你不必编写自己的线程管理器,这可能会被bug所困扰。如果你的程序需要同时运行多个线程,这一点特别有用。例如,你想一次执行两个线程,你可以很容易地这样做:
这个例子可能很简单,但是试着想象一下,“hello world”行包含了一个繁重的操作,并且您希望该操作同时在多个线程中运行,以提高程序的性能。这只是一个例子,还有很多情况下,您希望调度或运行多个线程,并使用ExecutorService作为线程管理器。
对于运行单个线程,我看不出使用ExecutorService有什么明显的优势。
jaxagkaj3#
Executor框架(内置线程池框架)克服了传统线程的以下限制。
*糟糕的资源管理即,它不断为每个请求创建新资源。对创建资源没有限制。使用Executor框架,我们可以重用现有资源并对创建资源施加限制。
*不稳健:如果我们继续创建新线程,我们将得到
StackOverflowException
异常,因此我们的JVM将崩溃。*间接费用创建时间:对于每个请求,我们需要创建新的资源。创建新的资源是非常耗时的。例如,线程创建〉任务。使用Executor框架,我们可以在线程池中构建。
线程池的优点
Source
6psbrbz94#
以下是一些好处:
1.执行器服务异步管理线程
1.使用Future可调用函数获取线程完成后的返回结果。
1.管理工作分配,以释放线程并从线程转售已完成的工作,以便自动分配新工作
1.并行处理fork-join框架
1.更好的线程间通信
1.关闭提供了完成所有线程分配工作的能力
1.调度执行器服务提供了产生可运行对象和可调用对象的重复调用的方法希望它能对您有所帮助
qjp7pelc5#
创建一个新线程真的那么昂贵吗?
作为一个基准测试,我刚刚使用
Runnable
创建了60,000个线程,这些线程都具有空的run()
方法。创建每个线程后,我立即调用其start(..)
方法。这花费了大约30秒的CPU密集活动时间。在响应this question时也做了类似的实验。这些实验的总结是,如果线程没有立即完成,并且累积了大量的活动线程(几千个),则会出现问题:(1)每个线程都有一个堆栈,因此您将耗尽内存,(2)操作系统可能会对每个进程的线程数施加限制,但not necessarily, it seems。因此,据我所知,如果我们讨论每秒启动10个线程,并且它们的完成速度都比新线程的启动速度快,我们可以保证不会超过这个速度太多,那么ExecutorService在可见的性能或稳定性方面不会提供任何具体的优势。(尽管用代码表达某些并发思想可能会更方便或更容易阅读。)另一方面,如果您可能每秒要调度数百或数千个任务,这可能会意外地发生,例如,如果您创建线程来响应对服务器的请求,而您的服务器接收到的请求的强度出现峰值。但是,例如,一个线程响应每个用户输入事件(按键,鼠标运动)似乎完全没问题,只要任务简短。
gpfsuwkq6#
ExecutorService还提供对FutureTask的访问,FutureTask将在后台任务完成后将结果返回给调用类。
ljsrvy3e7#
在java 1.5版本之前,Thread/Runnable是为两个独立的服务设计的
1.工作单位
1.该工作单元的执行
ExecutorService通过将Runnable/Callable指定为工作单元并将Executor指定为执行(使用生命周期)工作单元的机制,将这两个服务分离
luaexgnf8#
执行器框架
Executor
只是一个接受Runnable
的接口。execute()
方法只能调用command.run()
或与使用Runnable
的其他类一起工作(例如线程)ExecutorService
接口,该接口扩展了Executor
并添加了用于管理-shutdown()
和submit()
的方法,该方法返回Future
About(https://stackoverflow.com/a/66082407/4770877)-get()
、cancel()
ScheduledExecutorService
扩展了ExecutorService
以计划执行任务Executors
类,它是为运行async
任务About(https://stackoverflow.com/a/49386140/4770877)提供ExecutorService
实现的工厂结论
使用
Thread
对CPU和内存来说是一项开销很大的操作。ThreadPoolExecutor
由任务队列(BlockingQueue
)和线程池(Worker
的集合)组成,它们具有更好的性能和API来处理异步任务a7qyws3x9#
创建大量线程而不限制最大阈值可能会导致应用程序用尽堆内存。因此,创建ThreadPool是更好的解决方案。使用ThreadPool,我们可以限制可以池化和重用的线程数。
Executors框架简化了在java中创建线程池的过程。Executors类使用ThreadPoolExecutor提供ExecutorService的简单实现。
来源:
What is Executors Framework