重点分享国外最新技术内容
介绍
随着当今处理器中可用内核数量的增加和对更高吞吐量需求的增加,多线程应用编程接口变得非常流行。Java提供了自己的多线程框架,称为执行器框架。
1.什么是执行者框架?
执行器框架包含一组有效管理工作线程的组件。执行器应用编程接口将任务的执行与要通过执行器执行的实际任务分离开来。这是生产者-消费者模型的实现。
Java.util.concurrent.Executors提供了一个创建工作线程线程池的工厂方法。
要使用Executor框架,我们需要创建一个线程池,并将任务提交给它执行。执行器框架的工作是调度和执行提交的任务,并从线程池中获取返回的结果。
想到的一个基本问题是,为什么我们在创建java.lang.Thread对象或者调用实现Runnable/Callable接口的程序的并行性时需要线程池?
答案来自两个基础:
为新任务创建新的线程会存在额外的线程创建以及销毁的开销。管理这些线程的生命周期会明显增加 CPU 的执行时间。不进行任何限制地为每个进程创建线程会导致创建大量线程。这些线程会占用大量内存并引起资源的浪费。当一个线程利用完 CPU 的时间片后另一个线程即将利用CPU的时间片时,CPU 会花费大量的时间来切换线程的上下文。所有这些因素都会导致系统的吞吐量下降。线程池通过保持线程活动并重用它们来克服这个问题。当提交给线程池的任务多于正在执行的线程时,这些额外的任务将被放入队列。一旦执行任务的线程有空空闲,它们将执行队列中的下一个任务。对于JDK提供的现成执行者来说,这个任务队列基本上是无界的。
2.执行者的类型
现在我们知道了什么是执行人,让我们来看看不同类型的执行人。
2.1 SingleThreadExecutor
这个线程池执行器只有一个线程。它用于以顺序方式执行任务。如果此线程在执行任务时由于异常而挂起,将创建一个新线程来替换此线程,后续任务将在新线程中执行。
ExecutorService executorService = Executors.newSingleThreadExecutor2.2 FixedThreadPool(n)
顾名思义,它是一个固定线程数的线程池。提交给执行器的任务由固定的n个线程执行,如果任务较多,则存储在LinkedBlockingQueue中。这个数字n通常与底层处理器支持的线程总数有关。
ExecutorService executorService = Executors.newFixedThreadPool(4);2.3缓存读取池
这个线程池主要用于执行大量短期并行任务的场景。与固定线程池不同,该线程池中的线程数量没有限制。如果所有线程都忙于执行任务,并且有新的任务到来,这个线程池将创建一个新的线程并将其提交给执行器。一旦其中一个线程变为空空闲,它将执行一个新任务。如果一个线程空空闲60秒,它们将结束其生命周期并从缓存中删除。
但是如果管理不合理或者任务不是很短,线程池就会包含大量的活动线程。这可能会导致资源中断,从而降低性能。
ExecutorService executorService = Executors.newCachedThreadPool;2.4调度执行程序
当我们有一个需要定期运行的任务时,或者当我们想要延迟一个任务时,使用这种类型的执行器。
ScheduledExecutorService scheduledExecService = Executors.newScheduledThreadPool(1);您可以使用scheduleAtFixedRate或scheduleWithFixedDelay在ScheduledExecutor中定期执行任务。
scheduledExecService.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) scheduledExecService.scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit)这两种方法的主要区别在于它们对周期性任务连续执行之间的延迟的响应。
ScheduleAtFixedRate:每当前一个任务结束时,任务都会以固定的时间间隔执行。
ScheduleWithFixedDelay:只有在当前任务完成后,延迟倒计时才会开始。
3.对未来物体的理解
您可以使用执行程序返回的java.util.concurrent.Future对象来访问提交给执行程序的任务的结果。未来可以被认为是执行者对调用者的回应。
Future<String> result = executorService.submit(callableTask);如上所述,提交给执行器的任务是异步的,即程序不会等待当前任务完成,而是直接进入下一步。相反,每当任务执行完成时,执行器就将其设置在这个Future对象中。
调用方可以继续执行主程序,当他需要提交任务的结果时,可以调用。方法来获取它。如果任务完成,结果将立即返回给调用者,否则调用者将被阻止,直到执行器完成执行操作并计算结果。
如果调用者不能无限期等待任务执行的结果,那么这个等待时间也可以定期设置。它可以通过Future.get(长超时,时间单位单位)方法实现,如果在指定的时间范围内没有返回结果,将引发TimeoutException。调用者可以处理这个异常并继续执行程序。
如果执行任务时出现异常,对get方法的调用将引发ExecutionException。
至于Future.get方法返回的结果,重要的是只有提交的任务实现了java.util.concurrent.Callable接口才会返回Future。如果任务实现了可运行接口,对。一旦任务完成,get方法将返回null。
另一个担忧是未来。取消(布尔MayInterruptionFrunning)方法。此方法用于取消已提交任务的执行。如果任务已经在执行,当mayInterruptIfRunning标志为真时,执行器将尝试中断任务的执行。
4.示例:创建并执行一个简单的执行器
我们现在将创建一个任务,并尝试在固定池执行器中执行它:
public class Task implements Callable<String> {私有字符串消息;
公共任务(字符串消息){ this.message = message}
@Overridepublic String调用引发异常{返回" Hello " + message +"!";}}
任务类实现了可调用接口,并将字符串类型作为返回值方法。此方法还可以引发异常。这种向执行器抛出异常的能力和执行器向调用者返回这个异常的能力非常重要,因为它有助于调用者了解任务执行的状态。
现在让我们执行这个任务:
public class ExecutorExample { public static void main(String[] args) {任务任务=新任务(“世界”);
ExecutorService ExecutorService = executors . NewFixedThreadPool(4);未来<。字符串>result = executorService.submit(任务);
请尝试{ System . out . println(result . get);} catch(中断异常|执行异常){System.out.println("执行提交的任务时出错");e.printStackTrace}
executorService.shutdown}}
我们创建了一个4线程的FixedThreadPool执行器,因为这个演示是在四核处理器上开发的。如果正在执行的任务执行大量的I/O操作或者花费很长时间等待外部资源,那么线程的数量可能会超过处理器的内核数量。
我们实例化任务类,并将其提交给执行者执行。结果由Future对象返回,然后我们在屏幕上打印出来。
让我们运行执行示例并查看其输出:
Hello World!如预期的那样,任务追加问候Hello,并通过Future对象返回结果。
最后,我们在executorService对象上调用shutdown来终止所有线程,并将资源返回给OS。
那个。shutdown方法等待执行器完成当前提交的任务。但是,如果要求立即关闭执行器而不等待,那么我们可以使用。shutdownNow方法。
任何要执行的任务都会将结果返回给java.util.List对象。
我们还可以通过实现Runnable接口来创建相同的任务:
public class Task implements Runnable{私有字符串消息;
公共任务(字符串消息){ this.message = message}
公共void run { System . out . println(" Hello "+message+"!");}}
当我们实现Runnable时,有一些重要的变化。
无法从 run 方法得到任务执行的结果。因此,我们直接在这里打印。 run 方法不可抛出任何已受检的异常。5. 总结由于处理器的时钟速度难以提高,多线程越来越成为主流。但是由于涉及的复杂性,很难处理每个线程的生命周期。
在本文中,我们展示了一个高效简单的多线程框架,即执行器框架,并解释了它的不同组成部分。我们还查看了在执行器中创建提交和执行任务的不同示例。
像往常一样,这个例子的代码可以在GitHub上找到。
和更多人分享右上角的按钮~
过来,点一个看再走~ ~ ~
1.《什么是多线程 多线程 Executor 框架是什么?》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《什么是多线程 多线程 Executor 框架是什么?》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/jiaoyu/710156.html