Concurrency Utilities(JSR236) 并发工具类,也是java规范
文章目录
- 1.1、预览
- 1.2、规范的目标
- 1.3、其他Java平台规范
- 1.4、Java EE并发工具类的专家组
- 1.5、文档约定
- 2.1、容器管理线程 VS 非容器管理线程
- 2.2、应用完整性
- 2.3、容器线程上下文
- 2.4、Java EE 连接器体系结构的用法
- 2.5、安全
- 3.1、ManagedExecutorService
- 3.3 ContextService
- 3.4、ManagedThreadFactory
1.1、预览
- Java T M ^{TM} TM平台企业版本(Java EE) 服务器容器(例如Enterprise Bean或Web组件容器)直接使用常见的Java SE并发API,例如java.lang.Thread或 java.util.Timer
- 服务器容器为Java EE应用程序组件(例如Servlet和Enterprise javaBeansTM (EJB T M ^{TM} TM)提供运行时支持,他们在应用程序组件代码与平台服务和资源自建提供一层。所有应用程序组件代码都在由容器管理线程上运行,每个容器通常期望对容器提供的对象的所有访问都发生在同一线程上。
- 由于这种行为,应用程序组件通常无法从不受容器管理的线程可靠第使用其他Java EE平台服务。
- Java EE产品提供者(请参阅Java EE 7规范的2.11章)还不鼓励以非托管方式使用资源,因为它可能会破坏平台旨在提供的企业功能,例如可用性,安全性和可靠性和可扩展性。
- 该规范提供了一个简单的,标准化的API,用于使用Java EE应用程序组件的并发性,而不会损害容器的完整性,同时仍保留Java EE 平台的基本有点。
1.2、规范的目标
- 规范开发的目标:
- 利用现有的适用Java EE平台服务,为应用程序组件提供者提供一个简单而灵活的API,以使用并发设计原则设计应用程序。
- 通过在JavaSE和Java EE平台之间提供一致性,使得Java SE开发人员可以轻松第迁移到Java EE平台。
- 允许应用程序组件提供者轻松第将并发添加到现有的Java EE 应用程序。
- 支持简单(通用)和高级并发模式,而不会牺牲可用性。
1.3、其他Java平台规范
- 该文档中引用其他规范
- Concurrency Utilities Specification (并发工具规范(JSR-166))
- Java EE Connector Architecture (Java EE 连接器体系结构)
- Java Platform Standard Edition (Java 平台标准版本)
- Java 2 Platform,Enterprise Endition,Management Specification(JSR-77) (java EE企业管理规范)
- Java Naming and Directory Interface T M ^{TM} TM (java命名和目录接口)
- Java Transaction API (java事务API)
- Java Transaction Service (java事务服务)
- JDBC T M ^{TM} TMAPI (JDBC API)
- Java Message Service (JMS) (java消息服务)
- Enterprise JavaBeans$^{TM} $(EJB)
1.4、Java EE并发工具类的专家组
- 该规范是Java EE并发实用程序专家组成成员协同工作的结果。专家组包括以下成员:Adam Bien, Marius Bogoevici (RedHat), Cyril Bouteille, Andrew Evers, Anthony Lai (Oracle), Doug Lea, David Lloyd (RedHat), Naresh Revanuru (Oracle), Fred Rowe (IBM Corporation), and Marina Vatkina (Oracle).
- 我们还有感谢前专家组成员对本规范的贡献,包括:Jarek Gawor (Apache Software Foundation), Chris D. Johnson (IBM Corporation), Billy Newport (IBM Corporation), Stephan Zachwiega (BEA Systems), Cameron Purdy (Tangosol), Gene Gleyzer (Tangosol), and Pierre VignJras.
1.5、文档约定
-
常规Times字体用于此规范规定的信息。
-
斜体Times字体用于包含描述性信息的段落,例如描述典型用法的注释或使用描述说明澄清文本的注释
-
这个是代码示例 public class Hello{ }
-
本规范的重点是为Java EE应用程序组件提供异步的功能,这主要是通过扩展在JSR-166下开发并在Java平台标准版(Java SE)中的java.util.concurrent包中找到的Concurrency Utilities API 来实现的。
-
Java SE 并发实用程序提供了可以扩展以支持1.2节中定义的大多数目标的API,在Java SE平台中熟悉此API的应用程序开发人员无需改动即可利用现有代码库和使用模式:
-
这个规范有几个方面
- Java EE应用程序服务器中集中式,可管理的java.util.concurrent.ExecutorService对象的定义和使用
- Java EE 应用程序中Java SE 并发实用程序的用法。
- 将Java EE 容器的运行时上下文信息传播到其他线程
- 在Java EE应用程序组件中管理和监控异步操作的生命周期
- 保留应用程序的完整性
2.1、容器管理线程 VS 非容器管理线程
- Java EE应用程序服务器需要资源管理,以便集中管理并保护应用程序组件免于消耗不必要的资源,这可以通过资源池和管理资源生命周期来实现,在服务器应用程序组件(例如Servlet或EJB)中使用Java SE并发实用程序(例如java.util.concurrent API , java.lang.Thread和java.util.Timer)存在问题,因为容器和服务器不了解这些资源。
- 通过扩展java.util.concurrent API, 应用程序服务器和Java EE容器可以知道所使用的资源并为异步操作提供适当的执行上下文。
- 这主要是通过提供主要 java.util.concurrent.ExecutorService接口来实现的
2.2、应用完整性
- 托管环境允许应用程序共存,而不会损害整个系统并使应用程序组件彼此隔离,管理员可以调整部署和运行时设置,以提供不同的服务质量,资源供应,任务调度等,JavaEE容器还未应用程序组件提供运行时上下文服务。当使用诸如java.util.concurrent中的并发实用程序时,这些上下文服务必须可用。
2.3、容器线程上下文
-
与其他Java EE服务(例如JDBC数据源,JMS提供程序和EJB)进行交互时,Java EE依赖于线程上可用的各种上下文信息,从非容器线程使用Java EE服务时,需要以下行为:
- 保存应用程序组件线程的容器上下文。
- 标识要保存和传播的容器的上下文
- 将容器上下文应用于当前线程
- 恢复线程的原始上下文
-
一个需要上下文的应用程序组件传播的上下文类型包括JNDI命名上下文,类加载器和安全信息,容器必须支持这些上下文类型的传播。另外,容器可以选择支持其他类型的上下文的传播。
-
各种Java EE体系结构元素,容器和并发构造之间的关系如图2-1所示
-
容器(在这里以单个矩形表示)为应用程序组件提供了与JavaEE标准服务安全交互的环境(在EJB/Web容器矩形正下方的矩形中表示),四个新的并发服务(由四个深灰色矩形表示)运行应用程序组件和Java 标准服务运行异步任务,而不会违反容器的规范。
-
图中的箭头说明了从Java EE平台的一部分到另一部分的各种流程。
-
-
图2-1 Java EE体系结构下的并发工具类图
2.3.1、上下文调用点
- 容器上下文和管理结构在运行时使用众所周知的接口上的各种调用点传播到组件业务逻辑。在整个规范中将引用这些调用点或回调方法(以下称为“任务”):
- java.util.concurrent.Callable
- call()
- java.lang.Runnable
- run()
- java.util.concurrent.Callable
2.3.1.1、可选上下文调用点
-
以下回调方法默认情况下在未指定的上下文中运行,但是如果需要,可以将其配置为上下文调用点:
- javax.enterprise.concurrent.ManagedTaskListener
- taskAborted()
- taskSubmitted()
- taskStarting()
- javax.enterprise.concurrent.Trigger
- getNextRunTime()
- skipRun()
- javax.enterprise.concurrent.ManagedTaskListener
-
不需要将容器上下文传播到调用这些方法的线程。这是为了避免在这些回调方法中可能不需要设置容器上下文时产生的开销,可以通过ContextService使这些方法成为上下文(请参阅以下部分),这可以使任何Java对象成为上下文。
2.3.2、上下文对象和任务
- 任务是Java EE java.util.concurrent.Callable和java.lang.Runnable接口的具体实现(有关java.util.concurrent.ExecutorService的信息,请求参阅Javadoc).任务是代表计算或某些业务逻辑的工作单元。
- 上下文对象是具有特定应用程序组件的线程上下文与之关联的任何Java对象实例(例如、用户身份)。
- 注意:此处引用的上下文对象和任务与Java EE平台规范(CDI)的上下文和依赖注入中定义的上下文对象不同。有关将CDI bean用作任务的信息,请参见第2.3.2.1节。
- 将任务实例提交到ExecutorService的托管实例时,该任务将成为上下文任务。当上下文任务运行时,该任务的行为就像仍在与它一起提交的容器中运行一样。
2.3.2.1、任务和上下文和依赖注入(CDI)
- CDI bean可以用作任务。如果此类任务本身是组件或使用各种CDI API动态创建的,则可以利用注入。但是,在将CDI bean用作做任务时,应用程序开发人员应该注意已下几点:
- 提交到ExecutorService的托管实例的任务可能在提交组件的生命周期之后仍在运行,因此,不建议将范围为@RequestScoped, @SessionScoped或@ConversationScoped的CDI bean用作任务,因此不能保证将在销毁CDI上下文之前完成。
- 范围为@ApplicationScoped或@Dependent的CDI bean可用作任务,但是,任务仍可能在提交组件的生命周期之外运行,例如在组件被销毁时。
- 注入到任务中的CDI bean的传递性关闭应遵循上述关于其范围的准则。
2.4、Java EE 连接器体系结构的用法
- Java EE 连接器体系结构(连接器)允许创建可插入任何兼容Java EE应用程序服务器的资源适配器。连接器规范提供了一个WorkManager接口,该接口允许资源适配器进行异步处理,它没有提供Java EE应用程序与适配器进行异步处理。它没有提供Java EE应用程序与适配器的WorkManager进行交互的机制。
- 该规范解决了Java EE 应用程序使用javax.enterprise.concurrent.ManagerExecutorService或java.util.concurrent.ExecutorService与javax.enterprise.concurrent.ManagedThreadFactory异步运行应用程序业务逻辑的需求,连接器javax.resource.work.WorkManager实现的目的是在适当时选择使用或包装此规范中的java.util.concurrent.ExecutorService或其他功能。
- 通过访问应用程序的JNDI上下文,资源适配器可以通过在JDNI全局命名空间中查找来访问以下各节中描述的每个受管对象(请求参阅连接器规范的10.3.2节)
2.5、安全
-
如Java EE规范中所定义,此规范在很大程序大将大多数安全性决策推迟到容器和Java EE 产品提供者。
-
如果容器支持安全上下文,则Java EE产品提供者必须将安全上下文传播到执行的线程。
-
与线程进行交互时,应用程序组件提供者使用本规范中提供的接口。如果Java EE产品提供者已经实现安全管理器,则可能不允许某些操作。
-
本节介绍了Java EE产品提供者要实现的四个编程接口(有关此处描述的每个角色的详细定义,请参阅EE2.11)。这些接口的实例必须通过容器作为托管对象提供给应用程序组件:
- 3.1节,“ManagedExecutorService” 用于从容器提交异步任务的接口
- 3.2节,“ManagedScheduledExecutorService” 用于计划任务以在给定延迟后运行或定期执行的接口。
- 3.3节,“ContextService” ,这个接口用于创建上下文对象
- 3.4节, “ManagedThreadFactory” 这个接口用于创建管理线程。
3.1、ManagedExecutorService
- javax.enterprise.concurrent.ManagedExecutorService是扩展java.util.concurrent.ExecutorService接口的接口,Java EE 产品提供程序提供此接口的实现,以允许应用程序组件异步运行任务。
3.1.1、应用程序组件提供的责任
-
应用程序组件提供者(应用程序开发者) (EE2.11.2)使用ManagedExecutorService实例和关联的接口来开发利用这些接口提供的并发功能的应用程序组件。使用Java命名和目录接口(JNDI)命名上下文(EE.5)或通过注入资源环境引入(EE.5.8.1.1)检索这些对象的实例
-
应用程序组件提供者可以使用资源环境引用来获取对ManagedExecutorService实例的引用,如下所示:
-
使用以下引用类型将应用程序组件环境中的对象赋值给javax.enterprise.concurrent.ManagedExecutorService引用,(有关如何在部署描述符中声明资源环境引用的信息,请参阅EE.5.8.1.3)
-
使用JNDI(EE.5.2)或通过使用资源注解(EE.5.8.1.1)进行资源注入,在应用程序组件环境是查询托管对象。
-
-
本规范建议(但不要求),在组件环境的资源类型的适当子上下文组织所有资源环境的引用,例如,所有ManagedExecutorService引用都应该绑定在java:comp/env/concurrent子上下文中。
-
组件通过实现java.lang.Runnable或java.util.concurrent.Callable接口来创建任务类,这些任务类通常与Java EE应用程序组件一起存储。
-
任务类可以选择实现javax.enterprise.concurrent.ManagedTask接口以提供执行属性,并注册一个javax.enterprise.concurrent.ManagedTaskListener实例以接收生命周期事件通知。执行属性允许配置和控制任务的各个方面,包括是否暂停线程上的任何当前事务并提供身份信息。
-
使用已定义的submit(),execute(), invokeAll() 或invokeAny()方法中的任何一个,任务实例都被提交到ManagedExecutor实例。任务实例将作为提交任务的Java EE容器实例的扩展运行,并且可以与本规范其他部分中定义的java EE资源进行交互
-
对于应用程序组件提供者来说,为每个必须的ManagedExecutorService标识并记录所需的行为和服务级别协议非常重要,以下示例说明该组件如何描述和利用多个执行的程序。
3.1.1.1、使用例子
- 在此示例中,应用程序组件在从Servlet执行两个异步操作,一个操作(报告程序)正在启动一项任务, 以生成长时间的运行的报告,另一个操作是短期运行的任务,可并行访问不同的后端数据库(构建器)
- 由于每种类型的任务都具有完全不同的运行的配置文件,因此使用两个不同的ManagedExecutorService资源环境引用是有意义的。使用应用程序组件的部署描述符中标记记录每个引用的属性,并在以后进行映射
3.1.1.1.1、(Reporter Task)报告任务
- Reporter Task是一个项长期运行的任务,与数据库进行通信以生成报告。使用ManagedExecutorService异步运行任务。然后,客户端可以轮询服务以获取结果。
3.1.1.1.2、资源的环境引用-Reporter Task
-
以下资源环境引用已添加到Web组件的web.xml文件中。该描述反映了所需的配置属性(请参阅3.1.14.1),或者,可以在Servlet代码中使用资源注解。
-
注意:使用描述来记录托管对象的配置属性是可选的,此处使用的格式仅为示例,Java EE规范的未来修订版可能会规范此类用法。
-
<resource-env-ref> <description> 该执行程序用于应用程序的报告程序任务。该执行者,具有以下要求: 上下文信息:本地命名空间 </description> <resource-env-ref-name> concurrent/LongRunningTasksExecutor </resource-env-ref-name> <resource-env-ref-type> javax.enterprise.concurrent.ManagedExecutorSerivce </resource-env-ref-type> </resource-env-ref>
3.1.1.1.3、任务定义-Reporter Task
-
任务本身仅使用对JDBC数据源的资源引用,并使用连接/使用/关闭模式,调用数据源时。
-
public class ReporterTask implements Runnable{ String reportName; public ReporterTask(String reportName){ this.reportName = reportName; } public void run(){ //运行这个报告 if("TransactionReport".equals(reportName)){ runTransactionReport(); }else{ runSummaryReport(); } } // 连接数据源 Datasource ds = ...; void runTransactionReport(){ try(Connection con = ds.getConnection();...){ //读取或写入数据 ... // 提交。 con.commit(); } } }
3.1.1.14、任务提交-ReporterTask
-
该任务由连接到Servlet的HTTP客户端启动。客户端指定报告名称和其他要运行的参数,任务的句柄(Future)被缓存,以便客户端可以查询报告的结果。任务完成后,Future将包含结果。
-
public class AppServlet extends HTTPServlet implements Servlet{ //缓存执行实例 @Resource(name="concurrent/LongRunningTasksExecutor") ManagedExecutorService mes; protected void doPost(HttpServlet req, HttpServletResponse resp) throws ServletException,IOException{ // 获取生成报告请求的入参 // 为响应组装头部信息 // 创建一个Task任务 Reporter reportFuture = new ReporterTask(reportName) // 提交任务到ManagedExecutorService中 Future reportFuture = mes.submit(reporterTask); //缓存future到某个位置(例如客户会话) // 客户端可以轮询服务器获取结果 // 状态返回给客户端 ... // 告诉用户这个报告已经提交了 } }
3.1.1.1.5、(Builder Tasks)建造任务
- 该servlet访问两个不同的数据源并汇总结果,然后再将页面内容返回给用户。与其同步访问数据,不如使用两个不同的任务并行完成数据。
3.1.1.1.6、资源环境引用- Builder Tasks
-
以下资源环境参考已添加到web组件的web.xml文件中。该描述反映了所需的配置属性(请参阅3.1.4.1).或者可以在Servlet代码中使用@Resource注解
-
注意:使用描述来记录托管对象的配置属性是可选的,此处使用的格式仅为示例,java EE规范的未来修订版可能会规范此类用法
-
<resource-env-ref> <description> 这个执行器用于程序的builder Task, 且需要如下要求: 本地命名空间,安全性 </description> <resource-env-ref-name> concurrent/BuilderExecutor </resource-env-ref-name> <resource-env-ref-type> javax.enterprise.concurrent.ManagedExecutorService </resource-env-ref-type> </resource-env-ref>
3.1.1.1.7、任务定义-- Builder Task
-
任务本身仅使用某种机制(例如JDBC查询)从持久性存储中检索数据。
-
该任务实现javax.enterprise.concurrent.ManagedTask接口,并通过IDENTITY_NAME属性提供一个可识别的名称,以允许系统管理员诊断问题。
-
public class AccountTask implements Callable<AccountInfo>,ManagedTask{ // 按需报告的请求ID。 String reqID; String accountID; Map<String,String> execProps; public AccountTask(String reqID, String accountID){ this.reqID = reqID; this.accountID = accountID; execProps = new HashMap(); execProps.put(ManagedTask.INDENTITY_NAME, getIdentityName()); } public AccountInfo call(){ // 从持久数据库取出账户数据 AccountInfo info = ...; return info; } public String getIdentityName(){ return "AccountTask: ReqID=" + reqID + ",Acct=" + accountID; } public Map<String, String> getExecutionProperties(){ return execProps; } public ManagedTaskListener getManagedTaskListener(){ return null; } } public class InsuranceTask implements Callable<InsuranceInfo>, ManagedTask{ // 按需报告的请求ID。 String reqID; String accountID; Map<String,String> execProps; public InsuranceTask(String reqID, String accountID){ this.reqID = reqID; this.accountID = accountID; execProps = new HashMap(); execProps.put(ManagedTask.INDENTITY_NAME, getIdentityName()); } public InsuranceInfo call(){ // 从持久数据库取出保险数据 AccountInfo info = ...; return info; } public String getIdentityName(){ return "InsuranceTask: ReqID=" + reqID + ",Acct=" + accountID; } public Map<String, String> getExecutionProperties(){ return execProps; } public ManagedTaskListener getManagedTaskListener(){ return null; } }
3.1.1.1.8、任务调用–Builder Tasks
-
任务是通过HTTP客户端对Servlet的请求按需创建的
-
public class AppServlet extends HttpServlet implements Servlet{ // 取出执行的实例 @Resource(name="concurrent/BuilderExecutor") ManagedExecutorService mes; protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException{ // 从请求对象获取accountNumber , requestID //为响应组装响应头 // 创建一个任务提交 Future<AccountInfo> acctFuture = mes.submit(new AccountTask(reqID, accountID)); Future<InsuranceInfo> insFuture = mes.submit(new InsuranceTask(reqID, accountID)); // 等待结果 AccountInfo accountInfo = acctFuture.get(); InsuranceInfo insInfo = insFuture.get(); //处理结果 } }
3.1.2、应用程序组装者的职责
- 应用程序组装程序(EE 2.11.3)负责将应用程序组件组装成一个完整的Java EE应用程序,并提供描述对托管对象的依赖性的组装指令。
3.1.3、部署者的职责
- 部署程序(EE 2.11.4)负责将应用程序组件部署到特定的操作环境中,按照本规范的术语,部署程序将安装应用程序组件,并将应用程序组件提供者和应用程序组装者定义的依赖项映射到具有正确定义的属性的委托的对象,有关详情信息,请参考EE.5.8.2
3.1.4、Java EE产品提供者的职责
- Java EE产品提供者的职责在EE.5.8.3中定义
- Java EE产品提供程序可以包括其他上下文(例如语言环境),这些上下文可以传播到调用javax.enterprise.concurrent.ManagedTaskListener接口中的回调方法的任务线程中。ManagedExecutorService实现可以添加任何其他上下文,并以任何方式提供配置这些上下文的方式,只要这些上下文不违反本规范的要求。
- 下一节说明Java EE产品提供者可能希望提供的一些可能的配置选项。
3.1.4.1、ManagedExecutorService配置属性
- 每个MangedExecutorService可以支持配置属性指定一个或多个运行时行为,Java EE产品提供者将确定适当的属性以及为其产品配置这些属性的方法。
3.1.4.2、配置的例子
- 本节和小节说明了Java EE产品提供者如何配置MangedExecutorService以及此类服务可以提供的可能的选项的一些示例。
- 提供者可以选择更简单的方法,也可以选择添加更多的功能,例如更高的服务质量,持久性,任务分区或共享线程池。
- Name:供部署者作参考服务名称可以是任意的
- JNDI 名称:标识服务实例的名称可以是任意的但是必须的,部署者使用此值将服务映射到组件的资源环境引用。
- Context: 对ContextService实例的引用(请参阅第3.3节)。上下文服务可用于定义上下文,以在运行任务时传播到线程。对于某些实现,可能需要具有多个ContextService实例,每个实例具有不同的策略。如果同时指定了Context和ThreadFactory属性,则应该忽略ThreadFactory配置的Context属性。
- ThreadFactory: 对ManagedThreadFactory实例的引用(请参阅第3.4节)。托管ThreadFactory实例可以创建具有不同属性(例如优先级)的线程
- Thread Use : 如果应用程序打算运行短期任务或长期任务,他们可以指定使用线程池或守护程序的线程。
- Hung Task Threshold(挂起任务的阈值):任务挂起之前可以执行的时间(以毫秒为单位)
- Pool Info : 如果执行程序是线程池,则可以定义各种线程池属性(基于Java java.util.concurrent.ThreadPoolExecutor类的属性)
- Core Size (核心线程数):即使处于空闲状态,保留在池中的线程数。
- Maximum Size(最大线程数) :池中允许的最大线程数(可以是无界的)。
- Keep Alive(保持活着): 当线程数大于核心大小时,允许线程保持空闲状态的时间。
- Reject Policy(拒绝策略): 执行者拒绝任务时使用的策略,在此示例中, 有两个策略可用:
- Abort(舍弃) : 当拒绝的时候抛出异常
- Retry and Abort( 重试和拒绝):自动提交给另一个示例,如果失败则中止。、
3.2.4.2.1、典型计时器
-
本示例描述了使用有边界的线程池的ManagedScheduledExecutorService的典型配置。只有10个计数器可以同时执行,并且如果他们在运行5秒钟以上,则视为挂起。这样的执行程序可以在应用程序之间共享,并且设计为运行时间很短的任务,例如将事务标记为超时后回滚。
-
ManagedScheduledExecutorService Name: 典型计时器 JNDI Name: concurrent/execsvc/Timer Context: concurrent/ctx/AllContexts ThreadFactory concurrent/tf/normal Thread Use Pooled Hung Task Threshold 5000ms Pool Info: core size : 2
Max Size : 10
Keep Alive : 3000msRejected Policy Abort (舍弃)
3.2.4.3、默认 ManagedScheduledExecutorService
- Java EE 产品提供者必须提供预配置的默认ManagedScheduledExecutorService, 以供JNDI名称为java:comp/DefaultManagedScheduledExecutorService的应用程序组件使用。此默认ManagedScheduledExecutorService从上下文应用程序组件传播到上下文类型必须包含命名上下文,类加载器和安全性信息。
3.2.5、系统管理员的职责
- 系统管理员(EE2.110.5)负责监视和监督运行时环境,在本规范范围内,这些职责可能包含:
- 监控当前挂起的任务
- 监控资源的使用(举个例子,线程数和内存)
3.2.6、生命周期
- ManagedScheduledExecutorService实例的生命周期由应用程序服务器集中管理,并且不能由应用程序更改。
- ManagedScheduledExecutorService实例可由多个组件和应用程序使用,当执行程序运行任务时,线程的上下文将更改为与提交任务的组件实例匹配。任务完成后,上下文将恢复,请参阅图3-1 托管线程池程序组件关系。
- 当应用程序或组件停止或应用程序服务器本身关闭时,ManagedScheduledExecutorService实例可能会被应用程序服务器终止或挂起。
3.2.6.1、Java EE 产品提供者的要求
- 本小节描述ManagedSheduledExecutorService提供程序的要求:
- 从ManagedScheduledExecutorService执行时,所有任务都将在提交任务的应用程序的组件。
- ManagedScheduledExecutorService的生命周期由应用程序服务器管理。ManagedScheduledExecutorService接口上的所有生命周期的操作都将引发java.lang.IllegalStateException异常,这包括在java.util.concurrent.ExecutorService接口中定义的以下方法:awaitTermination(), isShutdown(), isTerminated(), shutdown() 和shutdownNow().
- 如果任务的组件未启动,则提交给执行者的所有任务都不得运行。
- 当Java EE 产品提供程序关闭ManagedScheduledExecutorService实例时:
- 所有尝试添加新任务都会被拒绝
- 如果任务没有执行,这些任务将会被取消
- 所有运行的任务都会interrupted
- 所有注册ManagedTaskListeners被调用
3.2.7、服务的Quality
- ManagedScheduledExecutorService实现必须支持至多一次的服务的Quality,至多一次的服务quality保证了一项任务最多可以运行一次。这种服务quality是运行任务的最有效的方法。以这种服务quality提交给执行者的任务本质上是瞬态的,不会持久存在,并且在流程重启后无法生存。
- 允许其他的服务quality,但是本规范尚未阐述
3.2.8、事务管理
- ManagedScheduledExecutorService实现必须使用javax.transaction.UserTransaction接口支持用户管理的全局事务划分,这在Java Transaction API规范中进行了描述。用户管理的事务允许组件手动控制全局事务划分边界。任务实现可以选择开始,提交和回滚事务,有关Java EE中事务管理的详细信息,请参阅EE4。
- 任务实例在提交线程的事务范围之外运行。执行线程中任何活动的事务都将被挂起。
3.2.8.1、Java EE产品提供者的要求
- 本小节描述ManagedScheduledExecutorService实现的事务管理要求。
- 必须在本地JNDI命名空间中将javax.transaction.UserTransaction接口作为环境条目提供:java:comp/UserTransaction(J2EE.5.7和J2EE.4.2.1.1)
- 使用begin()方法激活事务时,所有资源管理器都必须使用UserTransaction实例进行注册
- 当事务使用commit()和rollback()方法结束时,执行程序负责协调提交和回滚
- 任务必须具有与提交任务的组件相同的使用事务的能力,例如,允许任务调用事务性企业Bean和使用@Transactional拦截器的托管Bean,如Java Transaction API规范中所定义。
3.2.8.2 应用程序组件提供者的要求
- 本小节描述了每个任务提供者实施的事务管理要求:
- 启动事务的任务实例必须在开始新的事务之前完成事务
- 任务提供者使用javax.transaction.UserTransaction接口划分事务。
- 使用UserTransaction接口的begin(),commit()和rollback() 方法来划分事务。
- 当实例处于活动事务中时,不得使用特定于资源的事务划分API(例如,如果在事务实例中登记了java.sql.Connection,则Connection.commit() 和 Connection.rollback()方法不能被使用)
- 任务实例必须在任务方法结束之前完成事务。
3.3 ContextService
- javax。enterprise.concurrent.ContextService允许应用程序创建上下文对象,而无需使用托管执行程序。ContextService使用java.lang.reflect包中的动态代理功能将应用程序组件容器上下文与对象实例相关联,该对象成为上下文对象(请求参见2.3.2节),并且每当调用上下文对象上的方法时,该方法便会与关联的应用程序组件实例的线程上下文一起执行。
- 上下文对象允许应用程序组件开发各种应用程序和服务。而这些应用程序和服务通常是Java EE平台中不可能实现的,例如工作流系统,与ManagedThreadFactory结合使用时,可以使用定制的Java SE平台ExecutorService实现。
- ContextService还允许非Java EE服务回调(例如JMS MessageListener和JMX NotificationListener)在监听器注册者的上下文中运行,而不是在实现提供者的未定义的线程上下文中运行。
3.3.1、应用程序组件提供者的职责
- 应用程序组件提供者(应用程序开发者)(EE2.11.2)使用ContextService实例创建上下文对象代理,使用Java命名和目录接口(JNDI)命名上下文(EE.5)或通过注入资源环境引用(EE.5.8.1.1)检索这些对象的实例。
- 应用程序组件提供者可以使用资源环境引用通过以下方式来获取ContextService实例
- 使用以下引用类型将应用程序组件环境中的条目分配给该引用:javax.enterprise.concurrent.ContextService.(有关如何在部署描述符中声明资源环境引用的信息,请参阅EE.5.8.1.2)
- 使用JNDI(EE.5.2)或通过使用@Resource注解(EE.5.8.1.1)进行资源注入,在应用程序组件环境中查找托管对象
- 本规范建议(但不要求)在组件环境的资源类型的适当子上下文中组织所有资源环境引用。例如,所有ContextService引用应在java:comp/env/concurrent子上下文中声明。
- 使用ContextService实例中createContextualProxy()方法创建上下文对象代理实例。上下文对象代理将作为创建代理的应用程序组件实例的扩展运行,并且可以与本规范其他部分中定义的Java EE容器资源进行交互。
- 对于应用程序组件提供者来说,为每个必须的ContextService识别并记录所需的行为和服务级别协议非常重要。以下示例说明了该组件如何描述和利用ContextService.
3.3.1.1 使用例子
- 本节提供一个示例,说明如何在应用程序组件内利用自定义ExecutorService
3.3.1.1.1、自定义ExecutorService
- 此示例演示如何从EJB使用单例Java SE ExecutorService实现(例如java.util.concurrent.ThreadPoolExecutor).在此示例中,使用参考ThreadPoolExecutor实现而不是Java EE产品提供程序随附的实现。
- 可以像创建任何Java对象一样创建自定义ExecutorService,为了使应用程序使用对象,可以使用单例或使用连接资源适配器访问。在此示例中,我们使用单例会话bean。
- 由于ExecutorService是一个单例的会话bean,所以我们可以利用几个EJB或Servlet实例获取它,ExecutorService使用从Java EE产品提供者的MangedThreadFacttory(请参阅第3.4节)创建的线程。ContextService用于确保任务在池中的工作线程之一上运行时将具有正确的组件上下文。
3.3.1.1.2、ExecutorService 单例
-
使用ExecutorService的getter创建一个单例会话Bean ExecutorAccessor。这个ExecutorAccessor应该包含在EJB模块或应用程序组件范围内的其他jar中。
-
@Singleton public class ExecutorAccessor{ private ExecutorService threadPoolExecutor=null; @Resource(name="concurrent/ThreadFactory") ManagedThreadFactory threadFactory; @PostConstruct public void postConstruct(){ threadPoolExecutor = new ThreadPoolExecutor(5,10,5,TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), threadFactory); } public ExecutorService getThreadPool(){ return threadPoolExecutor; } }
3.3.1.1.3、CreditReport Task (信用报告任务)
- CreditReport任务从给定的信用机构检索给定的税号的信用报告。EJB业务方法并行调用多个任务。
3.3.1.1.4、资源环境的引用
-
这个例子引用ContextService和ManagedThreadFactory
-
注意:使用描述来记录托管对象的配置属性是可选的,此处使用的格式仅仅是示例。Java EE规范的未来修订版可能会规范此类用法。
-
<resource-env-ref> <description> 此ThreadFactory用于单例的ThreadPoolExecutor,优先级为正常,上下文信息:NA </description> <resource-env-ref-name> concurrent/ThreadFactory </resource-env-ref-name> <resource-env-ref-type> javax.enterprise.concurrent.MangedThreadFactory </resource-env-ref-type> </resource-env-ref> <resource-env-ref> <description> 此ContextService与信用报告组件正在使用的自定义ThreadPoolExecutor结合使用。此ContextService具有以下要求: 上下文信息:本地命名空间,安全 </description> <resource-env-ref-name> concurrent/AllContexts </resource-env-ref-name> <resource-env-ref-type> javax.enterprise.concurrent.ContextService </resource-env-ref-type> </resource-env-ref>
3.3.1.1.5、Task定义
-
此任务将请求记录在数据库中,该数据库需要本地命名空间才能找到正确的数据源。它还利用Java 身份验证和授权API(JAAS),从当前线程中检索用户的身份,以便审核对信用报告的访问。
-
public class CreditScoreTask implements Callable<Long>{ private long taxId; private int agency; public CreditScoreTask(Long taxId, int agency){ this.taxId = taxId; this.agency = agency; } public Long call(){ // 使用用户身份将请求记录在数据库中 // 使用本地命名空间去定位数据库 Subject currentSubject = Subject.getSubject(AccessController.getContext()); logCreditAccess(currentSubject, taxId, agency); // 使用web服务器去取出具体信用分数 return getCreditScore(taxId, agency); } ... }
3.3.1.1.6、Task 调用
-
LoanCheckerBean是一个无状态的会话EJB,它当中一个方法根据taxId从三个不同机构取出信用分数。它将使用三个线程完成此项任务,包括EJB线程。
-
当EJB线程正在取出其中一个信用分数,其他两个线程也正在取出其他两个分数。
-
class LoanCheckerBean{ @Resource(name="concurrent/AllContexts") ContextService ctxSvc; @EJB private ExecutorAccessor executorAccessor; public long[] getCreditScores(long taxId){ // 取出一个单例的线程池,它被包装在ExecutorCompletionService之中 ExecutorCompletionService<Long> threadPool = new ExecutorCompletionService<Long>(executorAccessor.getThreadPool()); //使用一个线程去取出其中一个信用分数,另两个处理其他两个信用分数 // 由于使用的是自定义执行程序,因为我们的任务取决于运行此方法的上下文,所有使用上下文任务。 CreditScoreTask agency1 = new CreditScoreTask(taxId,1); Callable<Long> agency2 = ctxSvc.createContextualProxy( new CreditScoreTask(taxId,2), Callable.class); Callable<Long> agency3 = ctxSvc.createContextualProxy( new CreditScoreTask(taxId, 3), Callable.class); threadPool.submit(agency2); threadPool.submit(agency3); long[] scores = {0,0,0}; try{ //在线程中取出一个信用分数值 scores[0] = agency1.call(); //取出其他两个信用分数 scores[1] = threadPool.take().get(); scores[2] = threadPool.take().get(); }catch(InterruptedException e){ //应用可能关闭 }catch(ExecutionException e){ // 在异步处理抛出执行异常 } return acores; } }
3.3.2、应用程序组装者的职责
- 应用程序组装程序(EE.2.11.3)负责将应用程序组件组装成一个完整的Java EE应用程序,并提供描述对托管对象的依赖性的组装指令。
3.3.3、部署者的职责
- 部署程序(EE.2.11.4) 负责将应用程序组件部署到特定的操作环境中,按照本规范的术语,部署程序将安装应用程序组件,并将应用程序组件提供者和应用程序组装者定义的依赖项映射到具有正确定义的属性的托管对象。有关详细信息,请参见EE.5.8.2
- 由ContextService实例创建的所有对象都需要将Java EE 容器上下文信息(请参阅第2.3节)传播到代理对象上调用的方法。
3.3.4、Java EE产品提供者的职责
- java EE产品提供者的职责已在5.8.3中定义,并且必须提供实现
- 以下定义的任何行为:
- 上下文代理实现的所有调用处理程序都必须实现 java.io.Serializable
- 如果应用没有部署或启动,调用任何代理接口都会失败,同时抛出异常。
- Java EE产品提供者可以将任何其他容器上下文添加到托管ContextService,并以任何方式提供配置这些上下文的方式,只要这些上下文不违反本规范的要求。
- 下一节说明Java EE产品提供者可能希望提供的一些可能的配置选项。
3.3.4.1、ContextService配置属性
- 每个ContextService可以支持配置属性指定的一个或多个运行时行为。Java EE产品提供者将确定适当的属性以及为其产品配置这些属性的方法。
3.3.4.2、配置例子
-
这个节或子节说明一些例子,Java EE Product提供者可以为ContextService提供配置信息,以及服务可以提供可选
-
应用程序组件可以使用资源环境引用直接使用ContextService,或者提供程序可以选择使用提供的上下文信息作为ManagedExecutorService,ManagedThreadFactory的默认上下文传播策略。 3.1.4.2、3.2.4.2和3.4.4.2节中介绍的配置示例引用了以下ContextService配置实例之一。
-
每个实例有以下属性
- Name : 供部署者用作参考的服务的任意名称
- JNDI name : 名称可以任意,但是这个字段必须的,去标识服务的实例,部署使用这个值服务映射组件资源环境的引用
- Context Info : 上下文信息可以被传播
- Security : 如果开启,传播容器的安全规则
- Locale: 如果开启,本地容器线程将会被传播
- Custom: 如果开启,自定义,线程本地数据可以被传播
3.3.4.2.1、All Contexts全部的上下文
ContextService | |
---|---|
Name: | AllContexts |
JNDI Name: | Concurrent/cs/AllContexts |
ContextInfo | Security Locale Custom |
3.3.4.2.2、OLTP Context
ContextService | |
---|---|
Name: | OLTPContexts |
JNDI Name: | Concurrent/cs/OLTPContexts |
ContextInfo | Security Custom |
3.3.4.2.3、No Contexts(没有上下文)
ContextService | |
---|---|
Name: | No Contexts |
JNDI Name: | Concurrent/cs/NoContexts |
ContextInfo |
3.3.4.3、默认 ContextService
- Java EE产品提供者必须提供预配置的默认的ContextService,以供JNDI名称为java:comp/DefaultContextService的应用程序组件使用。此默认ContextService从上下文应用程序组件传播的上下文类型必须包括命名上下文,类加载和安全性信息。
3.3.5、事务管理
- 上下文动态代理使用javax.transaction.UserTransaction接口支持用户管理的全局事务划分,这在Java Transaction API 规范中进行了描述,默认情况下,代理方法会挂起线程上的所有事务上下文,并允许组件手动控制全局事务划分边界,上下文对象可以选择开始,提交和回滚事务,有关Java EE中事务管理的详细信息,请参阅EE.4
- 通过在创建上下文代理对象时使用执行属性,应用程序组件可以选择不挂起线程上的事务上下文,并且任务使用的任何资源都将加入事务,有关详情信息和示例,请参考Java doc中的 javax.enterprise.concurrent.ContextService接口。
3.3.5.1、Java EE 产品提供者的要求
- 本小节描述了启用事务管理(这是默认行为)时,ContextService实现的事务管理要求。
- 必须在本地JNDI命名空间中将javax.transaction.UserTransaction接口作为环境条目提供:java:comp/UserTransaction(EE.5.10和EE.4.2.1.1)
- 当使用begin()方法激活事务时,所有资源管理器都必须使用UserTransaction实例进行注册。
- 当事务使用commit()和rollback()方法结束时,执行程序负责协调提交和回滚。
- 任务必须具有与提交任务的组件相同的使用事务的能力,例如,允许任务调用事务性企业bean和使用@Transactional拦截器的托管bean,如Java Transaction APi 规范中所定义。
3.3.5.2、应用组件提供者的要求
- 本小节描述了在启用事务管理时(这是默认行为),每个任务提供者实施的事务管理器要求
- 启动事务的任务实例必须在开始新事务之前完成事务。
- 任务提供者使用javax.transaction.UserTransaction接口划分事务
- 使用UserTransaction接口的begin(), commit()和rollback()方法来划分事务。
- 当实例处于活动事务中时,不得使用特定于资源的事务划分API(例如,如果在事务实例中登记了javax.sql.Connection,则不得使用Connection.commit() 和Connection.rollback()方法使用)
- 任务实例必须在任务方法结束之前完成事务
- 有关在任务中使用UserTransaction的示例,请参见3.1.8.2.1节
3.4、ManagedThreadFactory
- javax.enterprise.concurrent.ManagedThreadFactory允许应用程序从Java EE产品提供程序创建线程实例,而无需直接创建新的java.lang.Thread实例。当需要高级的专用执行模式时,此对象允许应用程序组件提供程序使用自定义执行程序,例如java.util.concurrent.ThreadPoolExecutor.
- Java EE产品提供者可以提供自定义线程实现,以向线程添加管理功能和容器上下文信息。
3.4.1、应用组件提供者的职责
- 应用组件提供者(应用程序开发人员)(EE2.11.2)使用javax.enterprise.concurrent.ManagedThreadFactory实例创建可管理的线程。使用Java命名和目录接口(JNDI)命名上下文(EE.5)或通过注入资源环境引用(EE.5.8.1.1)来检索ManagedThreadFactory实例。
- 应用程序组件提供程序可以使用资源环境引用来获取对ManagedThreadFactory实例的引用,如下所示:
- 使用以下引用类型将应用程序组件环境中的条目分配给引用:javax.enterprise.concurrent.ManagedThreadFactory.(有关如何在部署描述中声明资源环境引用的信息,请参阅EE.5.8.1.2)
- 本规范建议(但不要求)在组件环境的资源类型的适当子上下文中组织所有资源环境引用,例如,所有ManagedThreadFactory引用都应该在java:comp/env/concurrent子上下文中声明。
- 使用JNDI(EE.5)或通过使用Resource批注(EE.5.8.1.1)进行资源注入,在应用程序组件环境中查找托管对象。
- 使用java.util.concurrent.ThreadFactory接口上的newThread(Runnable r)方法创建新线程
- 应用程序组件线程有权中断该线程,对线程的所有其他修改均受到安全管流程(如果存在)的约束
- 所有线程都是上下文相关的(请参见第2.3节)。当使用Thread.start()方法启动线程时,执行的Runnable将与创建ManagedThreadFactory实例的应用程序组件实例的上下文一起运行。
- 如果MangedThreadFactory实例已经停止了,则对new Thread()的所有后续调用都必须抛出java.lang.IllegalStateException
- 注意:可以从应用程序组件中的多个线程调用ManagedThreadFactory实例,每个线程具有不同的内容上下文(例如,用户身份),通过始终应用ManagedThreadFactory创建者的上下文,每个线程具有抑制的上下文,如果每个线程需要不同的上下文,请使用ContextService创建上下文对象(请参见3.3节)。
3.4.1.1、使用例子
- 在这个例子中,一个应用组件使用后台守护线程任务去dump内容事件写到数据库日志中,非类似3.2.1.1.1节中定时器的例子
- 使用应用程序组件的部署描述符中的标记记录ManagedThreadFactory引用的属性,然后由Deployer进行映射。
3.4.1.1.1、日志的任务
- 日志任务是一个长期运行的任务,它有着与servlet相同的生命周期,它持续监视队列并等待事件到数据库日志,使用以下命名控制其生命周期javax.servlet.ServletContextListener.
3.4.1.1.2、资源环境引用
-
web组件的web.xml添加了如下资源环境引用。这个web.xml描述符反映必要的配置属性(参阅3.4.4.2节),或者是,可以在Servlet代码中加入@Resource的资源注解。
-
注意:使用描述来记录托管的对象的配置属性是可选的,此处使用的格式仅是示例,Java EE规范的未来修订版可能会规范此类用法
-
<resource-env-ref> <description> ManagedThreadFactory为应用日志任务创建一个新的线程 ManagedThreadFactory有以下要求 上下文信息:本地命名空间 </description> <resource-env-ref-name> concurrent/LoggerThreadFactory </resource-env-ref-name> <resource-env-ref-type> javax.enterprise.concurrent.ManagedThreadFactory </resource-env-ref-type> </resource-env-ref>
3.4.1.1.3、任务定义
-
任务本身仅使用对JDBC数据源的资源引用,并在调用数据源时使用连接/使用/关闭模式
-
public class LoggerTask implements Runnable{ DataSource ds = ...; public void run(){ // 等待数据和记录它 while(!Thread.interrupted()){ logEvents(getData(), ds); } } void logEvents (Collection data, DataSource ds){ // 遍历数据和打印每一行 for(...){ try(Connection con = ds.getConnection();...){ // 写数据 ... // 提交 con.commit(); } } } }
3.4.1.1.4、任务提交
-
使用javax.servlet.ServletContextListener进行任务启动或停止
-
public class CtxListener implements ServletContextListener{ Thread loggerThread = null; @Resource(name="concurrent/LoggerThreadFactory") ManagedThreadFactory threadFactory; public void contextInitialized(ServletContextEvent scEvent){ LoggerTask logger = new LoggerTask(); Thread loggerTask = threadFactory.newThread(logger); loggerThread.start(); } public void contextDestroyed(ServletContextEvent scEvent){ // 当它不在可用时候,中断我们的记录器任务 // 服务器也将为我们执行此操作 if(loggerThread !=null){ loggerThread.interrupt(); } } }
3.4.2、应用组装的职责
- 应用组装者的职责是组装应用组件成一个完整的Java EE application 和提供组装托管对象依赖的描述
3.4.3、开发者的职责
- 部署程序(EE.2.11.4) 负责将应用程序组件部署到特定的操作环境中。按照本规范的术语,部署程序将安装应用程序组件,并将应用程序组件提供者和应用程序组装者定义的依赖项映射到具有正确定义的属性托管的对象,有关详情信息,请参看EE.5.8.2.
3.4.5、Java EE产品提供者的职责
- newThread()方法返回一个线程必须实现MangeableThread接口。
- 当一个ManagedThreadFactory实例停止时,例如当一个组件创建之后停止,或当应用服务器关闭时,所有使用newThread()创建的线程都会被打断,同时这些线程在调用ManageableThread 的isShutdown()方法必须返回true
- 注意:目的是防止访问不再可用的组件。
- 如果ManagedThreadFactory实例创建的线程,但是在ManagedThreadFactory线程关闭之后才启动,这个时候,这些线程需要启动interrupted状态,同时调用Manageable接口的isShutdown()方法,必须返回true。
- 需要将ManagedThreadFactory实例创建的所有的线程将容器上下文信息(请参见第2.3节)传播到线程的Runnable。
- Java EE 产品提供者可以向托管ManagedThreadFactory添加任何其他容器上下文,并以任何方式提供配置这些上下文的方法,只要这些上下文不违反本规范的要求。
- 下一节说明Java EE产品提供者可能希望提供的一些可能的配置选择。
3.4.4.1、ManagedThreadFactory配置属性
- 每个托管ManagedThreadFactory可能支持配置的属性指定的一个或多个运行时行为。Java EE产品提供者将确定适当的属性以及未其产品配置的这些属性的方法。
3.4.4.2、配置示例
- 下面小结说明java EE 产品提供者对于ManagedThreadFactory可以配置可能属性,服务可以提供:
- 应用程序组件可以使用资源环境引用直接使用ManagedThreadFactory,或者提供程序可以选择使用作为ManagedExecutorService或ManagedScheduledExecutorService实例的默认上下文传播策略提供的上下文信息,第3.1.4.2节和第3.2.4.2节中介绍的配置实例引用了随后的ManagedThreadFactory配置示例之一。
- 每个例子都有如下属性:
- Name: 供部署者用作参考的服务的任意名称。
- JNDI name : 标识服务实例的任意名称,但必填,部署者使用此值将服务映射到组件的资源环境的引用
- Context: 对ContextService实例的引用(请参阅第3.3节)。上下文服务可用的定义上下文,以在运行任务时传播到线程。对于某些实现,可能需要具有多个ContextService实例,每个实例具有不同的策略。
- Priority: 分配给线程的优先级(数字越大,优先级越高)。有关如何使用此值的详情信息,请参阅java.lang.Thread Java api文档.
3.4.4.2.1 正常线程
-
此配置示例说明了一个典型的ManagedThreadFactory,它创建了具有所有可用上下文信息的普通优先级线程。
-
ManagedThreadFactory Name: Normal Threds JNDI Name: Concurrent/tf/normal Context: Concurrent/cf/AllContexts Priority 5(正常)
3.4.4.2.2、OLTP线程
-
此配置示例描述了一个ManagedThreadFactory, 它创建的优先级高于正常优先级的线程可以用于OLTP类型的请求。
-
ManagedThreadFactory Name: OLTP Threads JNDI Name : Concurrent/tf/OLTP Context: Concurrent/cf/AllContexts Priority: 6
3.4.4.2.3、长时间运行的线程
-
ManagedThreadFactory Name: 长时间运行Task线程任务 JNDI Name: concurrent/tf/longRunningThreads Context Concurrent/cf/AllContexts Priority 4
3.4.4.3、默认 ManagedThreadFactory
- Java EE 产品提供者必须以JNDI名称java:comp/DefaultManagedThreadFactory提供一个预配置的默认ManagedThreadFactory,供应用程序组件使用。此默认ManagedThreadFactory从上下文化应用程序组件传播的上下文类型必须包含命名上下文,类加载器和安全性信息。
3.4.5、系统管理员的职责
- 系统管理员(EE2.11.5)负责监视和监督运行时环境在本规范的范围内,这些职责可能包含:
- 监视挂起的任务
- 监视资源使用情况(例如,线程和内存)
3.4.6、事务管理
- ManagedThreadFactory实现必须使用javax.transaction.UserTransaction接口用户管理的全局事务管理划分,该接口在Java Transaction API规范中进行了描述,并且具有与EJB bean 管理的事务划分相似的语义(请参阅Enterprise JavaBeans规范)。用户管理的事务允许组件手动控制全局事务划分边界。任务实现可以选择开始,提交和回滚事务,有关Java EE 中事务管理的详情信息,请参阅EE.4
- 任务实例在提交线程的事务范围之外运行。执行线程中任何活动的事务都将被挂起。
3.4.6.1、Java EE 产品提供者的要求
- 本小节描述ManagedThreadFactory实现的事务管理要求。
- 必须使用javax.transaction.UserTransaction接口在本地JNDI命名空间中作为环境条目可用:java:comp/UserTransaction(EE5.10和EE4.2.1.1)
- 当使用begin()方法激活事务时,所有资源管理器都必须使用UserTransaction实例进行注册。
- 当事务使用commit()和rollback()方法结束时,执行程序负责协调提交和回滚
- 任务必须具有与提交任务的组件相同的使用事务的能力,例如,允许任务调用事务性企业bean和使用@Transactional拦截器的托管的bean,如Java Transaction API规定中所定义。
3.4.6.2、应用组件提供者的要求
- 本小节描述了每个任务提供者实施的事务管理要求。
- 启动事务的任务实例必须在开始新事务之前完成事务。
- 任务提供者使用javax.transaction.UserTransaction接口划分事务。
- 使用UserTransaction接口的begin(), commit()和rollback()方法来划分事务。
- 当实例处于活动事务时,不得使用特定于资源的事务划分API(例如,如果在事务实例中登记了javax.sql.Connection,则不得使用Connection.commit()和Connection.rollback()方法使用)
- 任务实例必须在任务方法结束之前完成事务
- 有关在任务中使用UserTransaction的示例,请参见3.1.8.2.1节。