Configuring managed executors

You can configure ManagedExecutorService instances to run asynchronous tasks with the specified thread context. The best practice is for Java™ EE applications to avoid directly managing their own threads; therefore, the ManagedExecutorService extends the JSE ExecutorService to provide a way to start asynchronous tasks within an application server environment. You might also configure the ManagedExecutorService to propagate various thread contexts that are relevant to Java EE applications to the thread of the asynchronous task.

About this task

Important: In Liberty, managed executors do not have their own thread pools. Tasks submitted to managed executor instances run on the common Liberty executor thread pool.
The ManagedExecutorService is available under the <concurrent-1.0> feature and enabled in the server.xml file as follows:
<featureManager>
    <feature>concurrent-1.0</feature>
</featureManager>

Propagation of context to the thread of a task that is run by the ManagedExecutorService is managed by the context service. A default instance of the context service (DefaultContextService) is created by the server and configured to propagate at least classloaderContext, jeeMetadataContext and securityContext. This default context service instance is used if a ManagedExecutorService is created without referring to a specific context service instance or configuring a context service instance directly within. For more information about context service instances, refer to the Configuring thread context service instances topic.

A default managed executor instance (DefaultManagedExecutorService) is available as java:comp/DefaultManagedExecutorService and uses the default context service instance for thread context capture and propagation.

Concurrency policies configure concurrency-related behaviors and constraints that apply to managed executors, such as maximum concurrency and maximum queue size. By default, managed executors use a concurrencyPolicy configuration element default instance, defaultConcurrencyPolicy, which has constraints that are unbounded. This default concurrency policy is used if you configure a managed executor without referring to or directly configuring a specific concurrencyPolicy element as a nested element. If multiple managed executors or other configuration elements refer to the same concurrencyPolicy element, the constraints in that policy apply across all of those managed executor instances and other configured resources. You can also configure a managed executor with a concurrency policy for long-running tasks, which applies to tasks with the LONGRUNNING_HINT execution property set to true. The configuration that is specified in the concurrencyPolicy element and the long-running concurrencyPolicy element applies to tasks submitted to run as soon as possible. The configuration does not apply to scheduled tasks.

Procedure

Example configuration in the server.xml file:

  • Managed executor service instance that is registered in JNDI with the name concurrent/execSvc, and that uses the default context service instance:
    <managedExecutorService jndiName="concurrent/execSvc"/>
  • Managed executor service instance with a maximum of five concurrent threads and a context service that is configured to propagate only the jeeMetadataContext context:
    <managedExecutorService jndiName="concurrent/execSvc1">
    	<contextService>
    		<jeeMetadataContext/>
    	</contextService>
           <concurrencyPolicy max="5"/>
    </managedExecutorService>
  • Managed executor service instance with context service configured to propagate classloaderContext and securityContext:
    <managedExecutorService jndiName="concurrent/execSvc2">
    	<contextService>
    		<classloaderContext/>
    		<securityContext/>
    	</contextService>
    </managedExecutorService>
  • Thread context service that is configured to propagate only the jeeMetadataContext context and a concurrency policy that specifies a maximum of four concurrent threads and a queue size of twenty, which are both shared by multiple managed executor service instances. The concurrent/execSvc4 managed executor has an additional concurrencyPolicy configuration element that specifies a maximum of two concurrent threads for long-running tasks:
    <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"/>
  • Thread context service that inherits from the previous example and adds propagation of classloaderContext context and is used by a managed executor service instance:
    <contextService id="contextSvc2" baseContextRef="contextSvc1">
    	<classloaderContext/>
    </contextService>
    
    <managedExecutorService jndiName="concurrent/execSvc5" contextServiceRef="contextSvc2"/>

Example

Managed executor service instances can be injected into application components (by using @Resource) or looked up with resource environment references (resource-env-ref). Regardless of how the instance is obtained, you can use it interchangeably as javax.enterprise.concurrent.ManagedExecutorService or its java.util.concurrent.ExecutorSerivce superclass.

  • Example that looks up the default managed executor:
    ManagedExecutorService executor = 
        (ManagedExecutorService) new InitialContext().lookup(
            "java:comp/DefaultManagedExecutorService");
    executor.submit(doSomethingInParallel);
  • Example that uses @Resource to inject as 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();
  • Example that uses @Resource to inject as 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();
  • Example <resource-env-ref> for java.util.concurrent.ExecutorService in the web.xml file:
    <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>
    
  • Example lookup that uses a resource environment reference:
    ExecutorService execSvc2 = 
        (ExecutorService) new InitialContext().lookup("java:comp/env/concurrent/execSvc2");
    
    futures = execSvc2.invokeAll(Arrays.asList(task1, task2, task3));
  • Example <resource-env-ref> for javax.enterprise.concurrent.ManagedExecutorService in the web.xml file:
    <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>
    
  • Example lookup that uses a resource environment reference and casts to ManagedExecutorService:
    ManagedExecutorService execSvc2 = 
        (ManagedExecutorService) new InitialContext().lookup("java:comp/env/concurrent/execSvc2");
    
    futures = execSvc2.invokeAll(Arrays.asList(task1, task2, task3));