Configure managed thread factories
We 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. We might also configure the ManagedThreadFactory to capture a thread context that is relevant to Java EE applications and propagate it to the new thread. 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 Configure 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.
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"/>
<managedThreadFactory jndiName="concurrent/threadFactory1"> <contextService> <securityContext/> </contextService> </managedThreadFactory>
<managedThreadFactory jndiName="concurrent/threadFactory2"> <contextService> <classloaderContext/> <jeeMetadataContext/> </contextService> </managedThreadFactory>
<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 (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());
@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();
@Resource(lookup="concurrent/threadFactory2") ManagedThreadFactory threadFactory; ... usage is same as previous example
<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>
<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>
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