配置受管执行程序

您可以配置 ManagedExecutorService 实例,以使用所指定线程上下文来运行异步任务。 最佳实践是 Java™ EE 应用程序避免直接管理它们自己的线程; 因此, ManagedExecutorService 扩展 JSE ExecutorService 以提供在应用程序服务器环境中启动异步任务的方法。 您还可以配置 ManagedExecutorService 以将与 Java EE 应用程序相关的各种线程上下文传播到异步任务的线程。

有关此任务

重要信息:Liberty中,受管执行程序没有自己的线程池。 提交到受管执行程序实例的任务在公共 Liberty 执行程序线程池上运行。
ManagedExecutorService 是在 <concurrent-1.0> 功能部件下提供的,并且在 server.xml 文件中启用,如下所示:
<featureManager>
    <feature>concurrent-1.0</feature>
</featureManager>

将上下文传播至 ManagedExecutorService 所运行任务的线程是由上下文服务管理。 服务器会创建上下文服务的缺省实例 (DefaultContextService),该实例配置为至少传播 classloaderContextjeeMetadataContextsecurityContext。 如果创建 ManagedExecutorService 时没有引用特定的上下文服务实例,也没有直接在其中配置上下文服务实例,那么将使用这个缺省上下文服务实例。 有关上下文服务实例的更多信息,请参阅“配置线程上下文服务实例”主题。

缺省的受管执行程序实例 (DefaultManagedExecutorService) 以 java:comp/DefaultManagedExecutorService 形式提供,并使用缺省的上下文服务实例来捕获和传播线程上下文。

并行策略用于配置要应用于受管执行程序的并行相关行为及约束,例如,最大并行度和最大队列大小。 缺省情况下,受管执行程序使用 concurrencyPolicy 配置元素的缺省实例 defaultConcurrencyPolicy,该实例具有无限制的约束。 如果您配置受管执行程序,但没有以嵌套元素形式引用或直接配置特定的 concurrencyPolicy 元素,那么将使用这个缺省并行策略。 如果多个受管执行程序或其他配置元素引用同一个 concurrencyPolicy 元素,那么该策略中的约束将应用于所有这些受管执行程序实例和其他已配置的资源。 另外,还可以为受管执行程序配置一个用于长时间运行的任务的并行策略,该策略将应用于 LONGRUNNING_HINT 执行属性设置为 true 的任务。 在 concurrencyPolicy 元素以及长时间运行 concurrencyPolicy 元素中指定的配置将应用于提交为尽快运行的任务。 此配置不适用于调度的任务。

过程

server.xml 文件中的示例配置:

  • 在 JNDI 中使用名称 concurrent/execSvc注册且使用缺省上下文服务实例的受管执行程序服务实例:
    <managedExecutorService jndiName="concurrent/execSvc"/>
  • 最多具有 5 个并发线程的受管执行程序服务实例以及配置为仅传播 jeeMetadataContext 上下文的上下文服务:
    <managedExecutorService jndiName="concurrent/execSvc1">
    	<contextService>
    		<jeeMetadataContext/>
    	</contextService>
           <concurrencyPolicy max="5"/>
    </managedExecutorService>
  • 配置了上下文服务以传播 classloaderContextsecurityContext的受管执行程序服务实例:
    <managedExecutorService jndiName="concurrent/execSvc2">
    	<contextService>
    		<classloaderContext/>
    		<securityContext/>
    	</contextService>
    </managedExecutorService>
  • 线程上下文服务,配置为仅传播 jeeMetadataContext 上下文和并行策略,该策略指定最多 4 个并发线程和 20 个队列大小,这两个线程都由多个受管执行程序服务实例共享。 concurrent/execSvc4 受管执行程序具有额外的 concurrencyPolicy 配置元素,该配置元素为长时间运行的任务指定最多两个并发线程:
    <contextService id="contextSvc1">
    	<jeeMetadataContext/>
    </contextService>
    
    <concurrencyPolicy id="normal" max="4" maxQueueSize="20"/>
    
    <concurrencyPolicy id="longRunning" max="2"/>
    
    <managedExecutorService 
        jndiName="concurrent/execSvc3" 
        contextServiceRef="contextSvc1" 
        concurrencyPolicyRef="normal"/>
    
    <managedExecutorService 
        jndiName="concurrent/execSvc4" 
        contextServiceRef="contextSvc1" 
        concurrencyPolicyRef="normal" 
        longRunningPolicyRef="longRunning"/>
  • 从先前示例继承并添加 classloaderContext 上下文传播并由受管执行程序服务实例使用的线程上下文服务:
    <contextService id="contextSvc2" baseContextRef="contextSvc1">
    	<classloaderContext/>
    </contextService>
    
    <managedExecutorService jndiName="concurrent/execSvc5" contextServiceRef="contextSvc2"/>

示例

可以将受管执行程序服务实例注入应用程序组件 (通过使用 @Resource) 或使用资源环境引用 (resource-env-ref) 进行查找。 无论如何获取实例,您都可以将其交替用作 javax.enterprise.concurrent.ManagedExecutorService 或其 java.util.concurrent.ExecutorSerivce 超类。

  • 查找缺省受管执行程序的示例:
    ManagedExecutorService executor = 
        (ManagedExecutorService) new InitialContext().lookup(
            "java:comp/DefaultManagedExecutorService");
    executor.submit(doSomethingInParallel);
  • 使用 @Resource 以注入为 java.util.concurrent.ExecutorService 的示例:
    @Resource(lookup="concurrent/execSvc1")
    ExecutorService execSvc1;
    
    ...
    
    // submit task to run 
    Future<Integer> future1 = execSvc1.submit(new Callable<Integer>() { 
    	public Integer call() throws Exception { 
    	  // java:comp lookup is possible because <jeeMetadataContext> is configured 
    		DataSource ds = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/ds1");
    		... make updates to the database 
    		return updateCount; 
    	} 
    });  
    Future<Integer> future2 = execSvc1.submit(anotherTaskThatUpdatesADatabase);  
    
    numUpdatesCompleted = future1.get() + future2.get();
  • 使用 @Resource 以注入为 javax.enterprise.concurrent.ManagedExecutorService 的示例:
    @Resource(lookup="concurrent/execSvc1")
    ManagedExecutorService execSvc1;
    
    ...
    
    // submit task to run 
    Future<Integer> future1 = execSvc1.submit(new Callable<Integer>() { 
    	public Integer call() throws Exception { 
    	  // java:comp lookup is possible because <jeeMetadataContext> is configured 
    		DataSource ds = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/ds1");
    		... make updates to the database 
    		return updateCount; 
    	} 
    });  
    Future<Integer> future2 = execSvc1.submit(anotherTaskThatUpdatesADatabase);  
    
    numUpdatesCompleted = future1.get() + future2.get();
  • web.xml 文件中的 java.util.concurrent.ExecutorService<resource-env-ref> 示例:
    <resource-env-ref>
    	<resource-env-ref-name>concurrent/execSvc2</resource-env-ref-name>
    	<resource-env-ref-type>java.util.concurrent.ExecutorService</resource-env-ref-type>
    </resource-env-ref>
    
  • 使用资源环境引用的查找示例:
    ExecutorService execSvc2 = 
        (ExecutorService) new InitialContext().lookup("java:comp/env/concurrent/execSvc2");
    
    futures = execSvc2.invokeAll(Arrays.asList(task1, task2, task3));
  • web.xml 文件中的 javax.enterprise.concurrent.ManagedExecutorService<resource-env-ref> 示例:
    <resource-env-ref>
    	<resource-env-ref-name>concurrent/execSvc2</resource-env-ref-name>
    	<resource-env-ref-type>javax.enterprise.concurrent.ManagedExecutorService</resource-env-ref-type>
    </resource-env-ref>
    
  • 使用资源环境引用并强制转换为 ManagedExecutorService 的查找示例:
    ManagedExecutorService execSvc2 = 
        (ManagedExecutorService) new InitialContext().lookup("java:comp/env/concurrent/execSvc2");
    
    futures = execSvc2.invokeAll(Arrays.asList(task1, task2, task3));