Frequently we need to spawn threads on server side.

Lets be mindful of the pitfalls of unmanaged threads used in Web Applications

  1. Unmanaged threads can use resources that may not be monitored by Application Server.
  2. Such threads do not have access to Runtime’s Contextual Information.
  3. Unmanaged threads can not be controlled from administration console of the server.
  4. Such threads can badly affect Application Server performance such as graceful shutdown or failure recovery.
  5. We should not register a ShutdownHook inside a Runtime container through unmanaged thread. So we should avoid subclasses of Spring AbstractApplicationContext which allows one accidentally call registerShutdownHook() from inside a spring bean.
  6. We should avoid all TaskExecutor classes which are provided with Spring Framework as they might invoke unmanaged threads.
  7. Avoid direct invocation of Quartz scheduler and the Timer classes.

Best Practices :

Always use server-managed threadpool services .

  1. ManagedExecutorService (extends J2EEManagedObject) is implemented by Bea/Gerenimo/Webshephere .
  2. CommonJ WorkManager is recommended for Tomcat.

Implementation Approach: 

Setup CommonJ :  The WorkManagerTaskExecutor class uses thread pools that are managed by the  application server, and delegates to a configured WorkManager instance.

Download commonj from http://commonj.myfoo.de

  • Copy commonj-twm.jar into ${TOMCAT_HOME}/lib directory.
  • Copy commonj-tomcat.jar into ${TOMCAT_HOME}/lib directory.

In the Tomcat’s configuration file context.xml add:

<Resource    name=”wm/ServiceWorkManager”

auth=”Container”
type=”commonj.work.WorkManager”
factory=”de.myfoo.commonj.work.FooWorkManagerFactory”
minThreads=”1″
maxThreads=”5″ />

In the web.xml add:

<resource-ref>
<res-ref-name>wm/ServiceWorkManager</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Now, in the spring configuration you can use something like:

<jee:jndi-lookup id=”workManager” jndi-name=”wm/ServiceWorkManager” />
<bean id=”workManagerTaskExecutor” >
<property name=”workManager” ref=”workManager” />
</bean>

Use the WorkManager instance :

1. Async JMS Listener  :

<jms:listener-container connection-factory=”myqcf”
task-executor=”workManagerTaskExecutor”
destination-resolver=”jndiDestinationResolver”
acknowledge=”transacted”
transaction-manager=”transactionManager”>
<jms:listener destination=”jms/queue.in” ref=”myMdb” />
</jms:listener-container>

2. Scheduler Job 

<beans:bean id=”jobLauncher”
class=”org.springframework.batch.execution.launch.support.SimpleJobLauncher”
p:jobRepository-ref=”jobRepository” >
<beans:property name=”taskExecutor”>
<beans:bean ref=” workManagerTaskExecutor”/>
</beans:property>
</beans:bean>

3. Execute a Callable from inside RestController / Servlet / MVCController / SOAPService

@RequestMapping(value = “/entities/add”, method = RequestMethod.POST)

public ResponseEntity<String> addEntity(@RequestBody final String request) { workItem = workManagerTaskExecutor.schedule(work, new WorkListener() { .. });

Advertisements