Configuring managed thread factories

You can configure ManagedThreadFactory instances to create new threads that run with a thread context of the thread from which the managed thread factory is looked up or injected. It is a best practice for Java™ EE applications to avoid directly managing their own threads; therefore, the ManagedThreadFactory extends the JSE ThreadFactory to provide a way to create managed threads within an application server environment. You might also configure the ManagedThreadFactory to capture a thread context that is relevant to Java EE applications and propagate it to the new thread.

About this task

The managed thread factory is available under the <concurrent-1.0> feature and enabled in the server.xml file as follows:
<featureManager>
	<feature>concurrent-1.0</feature>
</featureManager>

Thread context capture and propagation 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 ManagedThreadFactory does not specify a context service. For more information about context service instances, refer to the Configuring thread context service instances topic.

A default instance of ManagedThreadFactory (DefaultManagedThreadFactory) is available as java:comp/DefaultManagedThreadFactory and uses the default context service instance for thread context capture and propagation.

Procedure

Example configuration in the server.xml file:

  • Managed thread factory that is registered in JNDI with the name concurrent/threadFactory, and that uses the default context service instance:
    <managedThreadFactory jndiName="concurrent/threadFactory" maxPriority="5"/>
  • Managed thread factory with context service configured to capture and propagate securityContext only:
    <managedThreadFactory jndiName="concurrent/threadFactory1">
    	<contextService>
    		<securityContext/>
    	</contextService>
    </managedThreadFactory>
  • Managed thread factory with classloaderContext and jeeMetadataContext:
    <managedThreadFactory jndiName="concurrent/threadFactory2"> 
    	<contextService>
    		<classloaderContext/>
    		<jeeMetadataContext/>
    	</contextService>
    </managedThreadFactory>
    
  • Thread context service that is shared by multiple managed thread factories:
    <contextService id="contextSvc1"> 
    	<jeeMetadataContext/>
    </contextService>
    
    
    <managedThreadFactory jndiName="concurrent/threadFactory3" 
    contextServiceRef="contextSvc1"/>
    
    
    <managedThreadFactory jndiName="concurrent/threadFactory4" 
    contextServiceRef="contextSvc1"/>

Example

Managed thread factories 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, it can be used interchangeably as javax.enterprise.concurrent.ManagedThreadFactory or java.util.concurrent.ThreadFactory.

  • Example that looks up the default managed thread factory:
    ManagedThreadFactory threadFactory =
        (ManagedThreadFactory) new InitialContext().lookup(
            "java:comp/DefaultManagedThreadFactory");
    // Create an executor that always runs tasks with the thread context of the managed thread factory
    ExecutorService executor = new ThreadPoolExecutor(
        coreThreads, maxThreads, keepAliveTime, TimeUnit.MINUTES,
        new ArrayBlockingQueue<Runnable>(workRequestQueueSize),
        threadFactory, new ThreadPoolExecutor.AbortPolicy());
  • Example that uses @Resource to inject as java.util.concurrent.ThreadFactory: :
    @Resource(lookup="concurrent/threadFactory2")
    ThreadFactory threadFactory
    ...
    
    // create a new thread
    Thread dailySalesAnalysisTask = threadFactory.newThread(new Runnable() {
      public void run() {
          // java:comp lookup is possible because <jeeMetadataContext> is configured
        DataSource ds = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/ds1");
        ... analyze the data
      }
    });
    dailySalesAnalysisTask.start();
  • Example that uses @Resource to inject as javax.enterprise.concurrent.ManagedThreadFactory:
    @Resource(lookup="concurrent/threadFactory2")
    ManagedThreadFactory threadFactory;
    
    ... usage is same as previous example
  • Example <resource-env-ref> for java.util.concurrent.ThreadFactory in the web.xml file:
    <resource-env-ref>
    	<resource-env-ref-name>concurrent/threadFactory1</resource-env-ref-name>
    	<resource-env-ref-type>java.util.concurrent.ThreadFactory</resource-env-ref-type>
    </resource-env-ref>
  • Example <resource-env-ref> for javax.enterprise.concurrent.ManagedThreadFactory in the web.xml file:
    <resource-env-ref>
    	<resource-env-ref-name>concurrent/threadFactory2</resource-env-ref-name>
    	<resource-env-ref-type>javax.enterprise.concurrent.ManagedThreadFactory</resource-
    env-ref-type>
    </resource-env-ref>
  • Example lookup that uses a resource environment reference:
    ManagedThreadFactory threadFactory =
      (ManagedThreadFactory) new InitialContext().lookup("java:comp/env/concurrent/threadFactory");
    // Create a scheduled executor that always runs tasks with the thread context of the managed thread factory
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(5, threadFactory);
    ... use executor to schedule tasks from any thread