Spring提供的线程池支持

标签: spring 线程池 | 发表时间:2012-07-04 11:10 | 作者:360zhi
出处:http://www.cnblogs.com/

核心提示:一旦企业应用越来越复杂时(比如,基于流程服务器的EIS),它们对相关技术也提出了更高的要求。在使用 EJB 3.0组件技术开发企业应用过程中,它们能够享受到EJB容器提供的线程池、任务调度(@Timeout)服务。现如今,运行于Web容器的Web应用、单独的桌面应用

一旦企业应用越来越复杂时(比如,基于流程服务器的EIS),它们对相关技术也提出了更高的要求。在使用 EJB 3.0组件技术开发企业应用过程中,它们能够享受到EJB容器提供的线程池、任务调度(@Timeout)服务。现如今,运行于Web容器的Web应用、单独的桌面应用也复杂到需要依赖于线程池、任务调度的这类服务,是时候实现贵族到平民的转变了。

过去,很多企业项目可能会自身实现这类底层的非功能性的服务。从Java SE 5.0开始,线程池服务(即,java.util.concurrent包)已经内置到JDK中。至于任务调度服务,其实,自从Java 2 SDK 1.3以来,Java 2就内置了用于任务调度的定时器(比如,java.util.Timer、javax.swing.Timer)。开源领域的Quartz Scheduler正是能够提供企业级任务调度服务的使能技术,而且EJB 2.x也加强了任务调度的支持。甚至,BEA同IBM合作开发了Timer and Work Manager for Application Servers技术规范(CommonJ),这是专门用来解决Java EE应用中的线程池、任务调度问题的。另外,JMX规范中也定义了javax.management.timer.TimerMBean,开发者借助于它能够实现定时JMX通知。

针对上述各种线程池、任务调度支持,Spring 2.0提供了统一的客户视图、抽象,这使得应用根本不用理会底层的具体实现和机制。本章将从分析Spring 2.0提供的线程池支持入手,并过渡到Spring 2.0对任务调度提供的支持当中,从而进入到下一章内容。

15.1  Spring提供的线程池支持

自从Spring 2.0开始,TaskExecutor接口被引入到Spring平台中,这主要受到Java SE 5.0中java.util.concurrent.Executor的影响。这一接口为各种线程池服务提供了抽象,它在统一客户视图方面起到了最重要的作用。无论是Spring 2.0内部实现中,还是各种基于Spring的企业应用,TaskExecutor的应用随处可见,其定义如下。

public interface TaskExecutor {

//异步或同步执行用户提交的任务

void execute(Runnable task);

}

开发者可以通过execute(Runnable task)方法将待执行的任务提交给TaskExecutor。依据不同的TaskExecutor接口实现,这一任务会以异步或同步的方式进行。如果是同步,则调用者一直处于阻塞状态,直到任务被执行完成。此时,调用者同目标任务的执行处于同一线程中,因此线程上下文信息能够传播到目标任务的执行过程中。如果是异步,则一旦提交完任务,调用者即可返回,并继续进行自身的其他操作。此时,调用者同目标任务的执行位于不同的线程中,因此线程上下文信息很可能不能够在它们之间共享。应用要合理选择同步或异步。比如,在调用execute()期间,如果采用Spring受管事务或Acegi提供的企业级安全性服务,则一旦同步或异步选用不当,事务的ACID属性将得不到保证,而且应用的安全性也得不到保障。

Spring 2.0内置的TaskExecutor接口实现见图15-1,图中除了SyncTaskExecutor外,其他实现都是采用异步方式执行提交的任务的。

                       

图15-1  TaskExecutor继承链

开发者是否还记得,第5章介绍的SimpleApplicationEventMulticaster,它使用了SyncTaskExecutor辅助完成事件的消费工作,其代码摘录如下。

public class SyncTaskExecutor implements TaskExecutor, Serializable {

//同步调用客户提交的任务

public void execute(Runnable task) {

      Assert.notNull(task, "Runnable must not be null");

     task. run();

}

}

SyncTaskExecutor的使用非常简单,下面给出了示例,摘自Eclipse taskexecutordemo项目。

TaskExecutor te = new SyncTaskExecutor();

te.execute(new LogRunner());

由于SyncTaskExecutor不存在任何属性,因此它的使用最简单。在使用这一实现的过程中,并不会处触发新线程的创建工作,因为提交的任务同调用者同处于一个线程中。相比之下,异步执行用户任务的SimpleAsyncTaskExecutor的使用复杂些,下面给出了示例代码。此时,它会启动新的Thread,并允许开发者控制并发线程的上限(concurrencyLimit),从而起到一定的资源节流作用。默认时,concurrencyLimit取值为–1,即不启用资源节流。

<bean id="simpleAsyncTaskExecutor"

class="org.springframework.core.task. SimpleAsyncTaskExecutor">

<property name="daemon" value="true" />

<property name=" concurrencyLimit" value="2" />

<property name="threadNamePrefix" value="simpleAsyncTaskExecutor" />

</bean>

在Spring 2.0内部实现中,JMS集成会使用SimpleAsyncTaskExecutor完成JMS消息监听器的注册、执行等工作,我们将在第16章介绍这方面的内容。每次用户提交新的任务给SimpleAsyncTaskExecutor时,它都会启动新的线程来响应客户请求。这意味着,它并没有提供线程池功能。更何况,在Java EE环境中,随便启动新的线程并不是推荐的做法,因为Java EE容器没有办法管理到这些线程。所以,我们要改进SimpleAsyncTaskExecutor。

Java SE 5.0引入了ThreadPoolExecutor、ScheduledThreadPoolExecutor。Spring 2.0借助于ConcurrentTaskExecutor和ThreadPoolTaskExecutor能够通过IoC配置形式自定义它们暴露的各个属性。比如,下面给出ThreadPoolTaskExecutor的使用示例,其暴露的各个属性其实是ThreadPoolExecutor的属性,这体现了DI容器的优势。

<bean id="threadPoolTaskExecutor"

class="org.springframework.scheduling.concurrent. ThreadPoolTaskExecutor">

<property name="corePoolSize" value="2" />

<property name="keepAliveSeconds" value="200" />

<property name="maxPoolSize" value="10" />

<property name="queueCapacity" value="60" />

</bean>

Spring 2.0在集成java.util.Timer任务调度机制过程中,还引入了TimerTaskExecutor。此时,用户提交的所有任务将交由Timer本身的单个线程执行,其示例配置如下。这一单个线程会以串行的方式完成用户提交给它的所有任务。

<bean id="timerTaskExecutor"

class="org.springframework.scheduling.timer. TimerTaskExecutor">

<property name="delay" value="10000" />

</bean>

在集成Quartz任务调度框架过程中,Spring引入了SimpleThreadPoolTaskExecutor。此时,用户提交的所有任务将交由Quartz维护的线程池执行,其示例配置如下。很显然,开发者能够控制这一线程池的具体细节。在使用Quartz实现任务调度过程中,它会使用内置的线程池处理任务。

<bean id="simpleThreadPoolTaskExecutor"

class="org.springframework.scheduling.quartz. SimpleThreadPoolTaskExecutor">

<property name="makeThreadsDaemons" value="true"/>

<property name="threadCount" value="5" />

<property name="threadNamePrefix" value="simpleThreadPoolTaskExecutor"/>

<property name="waitForJobsToCompleteOnShutdown" value="true" />

</bean>

如果开发者在使用BEA WebLogic 9+和IBM WebSphere 6+版本的Java EE应用服务器,则应用通过JNDI树还能够获得CommonJ提供的Java EE容器受管连接池。我们之前使用的TimerTaskExecutor、SimpleThreadPoolTaskExecutor并没有使用到容器受管连接池,而且它们也不能够使用到Java EE应用的上下文信息,而CommonJ却可以做到。甚至,CommonJ同时支持同步和异步处理用户提交的任务。当然,CommonJ并不是Java EE规范的组成部分,因此只有BEA和IBM客户才能够享受到这一待遇,即WorkManagerTaskExecutor。

WorkManagerTaskExecutor的示例配置如下。我们可以在很多场合使用到这一容器受管的线程池服务,比如,当使用Spring JMS集成开发消息应用时,开发者可以在WebSphere或WebLogic中使用WorkManagerTaskExecutor提供的线程池服务。

<bean id="workManagerTaskExecutor"

class="org.springframework.scheduling.commonj. WorkManagerTaskExecutor">

<property name="workManagerName" value="jndi/workManager" />

</bean>

 

本文链接

相关 [spring 线程池] 推荐:

Spring提供的线程池支持

- - 博客园_首页
核心提示:一旦企业应用越来越复杂时(比如,基于流程服务器的EIS),它们对相关技术也提出了更高的要求. 在使用 EJB 3.0组件技术开发企业应用过程中,它们能够享受到EJB容器提供的线程池、任务调度(@Timeout)服务. 现如今,运行于Web容器的Web应用、单独的桌面应用. 一旦企业应用越来越复杂时(比如,基于流程服务器的EIS),它们对相关技术也提出了更高的要求.

如何使用Spring开发和监控线程池服务

- - ImportNew
线程池对执行同步或异步的任务很重要. 本文展示如何利用Spring开发并监控线程池服务. 创建线程池的其他两种方法已讲解过. 第1步:创建Maven工程. (可以使用Maven或IDE的插件创建). 将Spring的依赖添加到Maven的pom.xml文件中. 使用下面的插件创建可执行jar包. 创建一个实现Runnable接口的新TestTask类.

使用SPRING中的线程池ThreadPoolTaskExecutor实现JAVA并发

- - Java - 编程语言 - ITeye博客
//线程池所使用的缓冲队列 . //线程池维护线程的最少数量 . //线程池维护线程的最大数量 . //线程池维护线程所允许的空闲时间 .  .      .      .      .

spring自带线程池使用不当导致的死锁问题

- - 海思
Spring自带线程池使用很方便,不过在相对复杂的并发编程场景中,使用时还是需要根据使用场景仔细考虑配置,否则可能会遇到本文中提及的坑. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-taskexecutor-block.

Java线程池

- - 企业架构 - ITeye博客
线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的. 在jdk1.5之后这一情况有了很大的改观. Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用. 为我们在开发中处理线程的问题提供了非常大的帮助.

Java 线程池

- - 编程语言 - ITeye博客
在项目中,系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互. 在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存周期很短的线程时,更应该考虑使用线程池. 使用线程池可以有效地控制系统中并发线程的数量,当系统中包含大量并发线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过此数.

java线程池分析

- - BlogJava-首页技术区
    在Java 5.0之前启动一个任务是通过调用Thread类的start()方法来实现的,任务的提于交和执行是同时进行的,如果你想对任务的执行进行调度或是控制 同时执行的线程数量就需要额外编写代码来完成. 5.0里提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接 池的线程池来执行任务.

Java线程池应用

- - CSDN博客架构设计推荐文章
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务. 2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机). Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具.

Java线程池总结

- - Java - 编程语言 - ITeye博客
  假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间. 当T1 + T3 远大于 T2时,采用多线程技术可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     线程池就是一个线程的容器,每次只执行额定数量的线程, 线程池作用就是限制系统中执行线程的数量.

Spring详解

- - CSDN博客架构设计推荐文章
Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(AOP)的容器框架.它的主要目的是简化企业开发.. PersonDaoBean 是在应用内部创建及维护的. 所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的.