java平台一直对并发程序设计和多线程有这很好的支持。但在早期这种支持也只是在应用层调用原生结构,这种方式最大的缺陷就是使这些原始构件有效的被调用;否则,应用将不能正确运行或者不能达到期望结果。
Executor框架自java1.5中被作为comcurrency包的一部分被引入。它是java多线程的一个抽象层实现,并且作为java中首个实用的并发框架被用来标准调用、在并行线程中调度、执行以及控制异步任务。执行规则在创建构造器的时候就已经被定义,之后executor按照之前设置好的规则来调用并发线程。
在java中Executor的实现使用线程池,该线程池由workder线程组成。由于worker线程的管理都由该框架来完成,因此和早先多线程方法来比内存开销小了很多。
图1:java Executor Service
在java1.5之前,多线程应用使用线程组、线程池或者自定义线程池,这样一来,整个线程管理需要程序员牢记以下几点责任:
-
线程同步
-
线程等待
-
线程join
-
线程锁
-
线程通知
-
处理死锁
以及更多在应用需求之外产生的并发执行问题。在实际项目实现过程中有时控制多线程应用是非常困难的。同时线程的表现行为也依赖与所在应用的部署和运行环境,因此,同一个应用在不同的部署环境下可能有不能的行为结果。例如,处理器速度、RAM内存大小、带宽都会直接影响多线程应用。所以我们在构建多线程架构之前都要谨记这些影响因素。
Java Executor框架为多线程应用提供了一个更加容易的抽象层。其中executor抽象层隐藏了并发执行部分,程序员只需要关注业务逻辑实现即可。在executor框架中所有的并行工作都被视为任务而不是看作简单的线程,所以此时应用只需要简单的处理Runnable实例(这是一组基本任务或并行工作的集合),接下来这些任务会被传给一个Executor来处理。ExecutorService接口继承了Executor接口。此外java Executor框架有生命周期方法来管理真个并发执行流程。
Executor通过使用Runnable或这Callable实例来创建任务。使用Runnable时,run方法并不返回任何值或者抛出异常;但是Callable在这方面提供了更多功能,它定义了一个call方法来允许返回计算值并且可在future处理中使用这个值,同时如果需要的话还可以抛出异常。
而FutureTask类又是另外一个重要的组件,该组件可以用来获取处理后的信息。该类的实例可以用来包装Callable或者Runnable。我们可以通过ExecutorService的submit方法的一个该类实例的返回值,同时我们还可以在调用execute方法前手动使用FutureTask来包装我们的任务。
以下是实现java ThreadPoolExecutor的功能步骤:
-
创建线程池
-
创建一个队列来存放所有还没有被分配给线程池中线程的任务
-
当队列中一个或多个任务不能被分配时用拒绝处理程序(Rejection handler)来处理。按默认拒绝策略,拒绝处理程序将简单的抛出一个RejectedExecutionException运行时异常,应用程序可以捕获或丢弃该异常
图2:Thread Pool Executor
下面的例子会展示executor框架的生命周期。这个例子仅覆盖基本的步骤和接口,还有更多的属性和子类来满足不同类型应用的需求。
下面的类实现了Runnable接口,它的实例将在下一小节的代码中被用作任务。
代码片段1:实现Runnable接口的类
代码片段2:实现Executor任务的类
接下来我们将描述在应用中实现java executor框架的步骤。
创建Executor
首先,我们需要创建一个Executor或者ExecutorService实例。Executor类有很多静态工厂方法来根据应用的不同需求创建ExecutorService。以下是两种创建executor服务的两种主要方式:
-
newFixedThreadPool()返回一个包含已初始化并且没有上限队列以及固定数量线程的ThreadPoolExecutor实例
-
newCachedThreadPool()返回一个包含无上限队列和无线程限制的ThreadPoolExecutor实例
第一种方式中执行过程中并未创建额外的线程。因此如果没有空闲线程可用那么任务将等待直到有空闲线程才能执行。在第二种方式中,已经创建的线程如果空闲则将被再利用,但是如果没有线程可用时将创建一个新的线程并将该线程加入到线程池中用来完成任务处理。对于空闲时间超过一个设定的超时时间以后,将被自动从线程池中移除。
下面是创建10个固定线程的线程池:
下面是创建缓冲线程池代码:
下面则是自定义线程池的例子。其中参数值由项目具体需求决定。这里线程池有8个核心线程可以并行处理,最大线程数为12。队列可以持有250个任务。这里有一点需要注意的是池的大小需要保持较大的值以满足所有任务。空闲时间限制保持在5毫秒。
创建一个或多个任务放入队列
创建executor完成之后紧接着就要创建任务了。创建一个或多个可以做为Runnable或Callable实例执行的任务。在这个框架中,所有的任务都是在队列中被创建和填充。当任务创建完成以后填充队列被提交并发执行。
提交任务到Executor
创建完ExecutorService和task之后,我们需要通过submit或者execute方法提交任务到executor。现在按照我们的配置,任务将被从队列中取出并发执行。例如,如果配置并发执行数为5,那么一次将从队列中取出5个任务来并发执行。该处理l直到队列中所有的任务都处理完才停止。
执行任务
接下来,实际的任务执行将由框架来管理。Executor负责对任务的执行、线程池、同步以及队列进行管理。如果线程池中线程数少于配置中的最小线程数,executor将按照要求创建新的线程来处理队列中的任务直到达到最小线程数为止;如果线程数大于配置的最小线程数,那么线程池将不会再创建线程。相反,任务将一直保持在队列中,直到有新的线程空闲来处理该请求。如果队列已满,则会创建一个新的处理线程,但换句话说这取决于创建executor使所使用用的构造函数。
关闭Executor
终止executor的方式是调用shutdown方法。同时我们可以选择平滑关闭或者直接关闭。
总结
经过以上的讨论,很明显并发框架是非常高效的并且在多线程应用中被广泛使用。这是java中引入的第一个并发框架,它为并发编程增加了一个新的维度。程序员通过使用executor框架增加了程序的灵活性,同时也避免了内存同步的开销而使程序更加稳定。
相关推荐
一、为什么要引入Executor框架? 1、如果使用new Thread(…).start()的方法处理多线程,有如下缺点: ① 开销大。对于JVM来说,每次新建线程和销毁线程都会有很大的开销。 ② 线程缺乏管理。没有一个池来限制线程的...
Executor框架是Java并发编程中的一个重要工具,它提供了一种管理线程池的方式,使得我们可以更方便地管理线程的生命周期和执行线程任务。 原子操作是指不可被中断的操作,要么全部执行成功,要么全部不执行。原子...
1. Java多线程学习(一)Java多线程入门 2. Java多线程学习(二)synchronized关键字(1) 3. Java多线程学习(二)synchronized关键字(2) 4. Java多线程学习(三...9. Java多线程学习(八)线程池与Executor 框架
Java是天生就支持并发的语言,支持并发意味着多线程,线程的频繁创建在高并发及大数据量是非常消耗资源的,因为java提供了线程池。这篇文章主要介绍下并发包下的Executor接口,Executor接口虽然作为一个非常旧的接口...
调用关系:Java线程一对一映射到本地操作系统的系统线程,当多线程程序分解若干任务,使用用户级的调度器(Executor框架)将任务映射为固定数量的线程,底层,操作系统吧、内核将这些线程映射到硬件处理器上。...
整我 学习使用异步套接字和java executor框架开发多线程网络应用程序。 帮助/参考
4、使用Executor框架 继承Thread类和实现Runnable接口是最基本的方式,但有一个共同的缺点:没有返回值。而Future Task解决了这个问题。Executor是JDK提供的一个多线程框架。 Java8创建一个新的执行线程有两种方法:...
主要介绍了Java并发框架:Executor API详解,随着当今处理器中可用的核心数量的增加, 随着对实现更高吞吐量的需求的不断增长,多线程 API 变得非常流行。 Java 提供了自己的多线程框架,称为 Executor 框架,需要的...
3、什么是多线程中的上下文切换?4、死锁与活锁的区别,死锁与饥饿的区别?5、Java 中用到的线程调度算法是什么?6、什么是线程组,为什么在 Java 中不推荐使用?7、为什么使用 Executor 框架?8、在 Java 中 ...
JUC(Java Util Concurrent)是Java中用于并发编程的工具包,提供了一组接口和类,用于处理多线程和并发操作。JUC提供了一些常用的并发编程模式和工具,如线程池、并发集合、原子操作等。 JUC的主要特点包括: ...
全书通过60多个简单而非常有效的实例,帮助读者快速掌握Java 7多线程应用程序的开发技术。学习完本书,你可以将这些开发技术直接应用到自己的应用程序中。 《Java 7并发编程实战手册》适合具有一定Java编程基础的...
通过将 MyRunnable 对象传递给 Thread 类...Executor 框架和线程池:用于管理和调度线程的执行。 通过合理地创建和管理线程,我们可以实现复杂的并发执行逻辑,提高程序的性能和响应能力,并确保线程之间的安全和协调。
java多线程、线程池详细教程,Executor框架的简单介绍。
第4章从介绍多线程技术带来的好处开始,讲述了如何启动和终止线程以及线程的状态,详细阐述了多线程之间进行通信的基本方式和等待/通知经典范式。 第5章介绍Java并发包中与锁相关的API和组件,以及这些API和组件的...
2. Java中如何实现多线程? 答:可以通过继承Thread类或实现Runnable接口来创建线程。另外,还可以使用Executor框架或线程池来管理线程。 3. Java中什么是抽象类? 答:抽象类是一种不能被实例化的类,只能作为其他...
第4章从介绍多线程技术带来的好处开始,讲述了如何启动和终止线程以及线程的状态,详细阐述了多线程之间进行通信的基本方式和等待/通知经典范式。第5章介绍Java并发包中与锁相关的API和组件,以及这些API和组件的...
前言多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的。线程池应运而生,成为我们管理线程的利器。Java 通过 Executor
6.1 在线程中执行任务 6.1.1 串行地执行任务 6.1.2 显式地为任务创建线程 6.1.3 无限制创建线程的不足 6.2 Executor框架 6.2.1 示例:基于Executor的Web服务器 6.2.2 执行策略 6.2.3 线程池 6.2.4 Executor...
第4章从介绍多线程技术带来的好处开始,讲述了如何启动和终止线程以及线程的状态,详细阐述了多线程之间进行通信的基本方式和等待/通知经典范式。第5章介绍Java并发包中与锁相关的API和组件,以及这些API和组件的...
了解多线程所带来的安全风险.mp4 从线程的优先级看饥饿问题.mp4 从Java字节码的角度看线程安全性问题.mp4 synchronized保证线程安全的原理(理论层面).mp4 synchronized保证线程安全的原理(jvm层面).mp4 单例问题...