27

I'm trying to get a handle on how to implement threading in a Java application that uses Spring for transaction management. I've found the TaskExecutor section in the Spring documentation, and ThreadPoolTaskExecutor looks like it would fit my needs;

ThreadPoolTaskExecutor

This implementation can only be used in a Java 5 environment but is also the most commonly used one in that environment. It exposes bean properties for configuring a java.util.concurrent.ThreadPoolExecutor and wraps it in a TaskExecutor. If you need something advanced such as a ScheduledThreadPoolExecutor, it is recommended that you use a ConcurrentTaskExecutor instead.

However I have no idea how to go about using it. I've been searching for good examples for awhile now with no luck. If anyone can help me out I would appreciate it.

Community
  • 1
  • 1
James McMahon
  • 48,506
  • 64
  • 207
  • 283

1 Answers1

36

It's pretty simple. The idea is that you have an executor object that's a bean, which is passed into whatever object wants to fire the new task (in a new thread). The nice thing is that you can modify what type of task executor to use just by changing the Spring config. In the example below I'm taking some example class (ClassWithMethodToFire) and wrapping it in a Runnable object to do the fire; you could also actually implement Runnable in a class of your own, and then in the execute method you'd just call classWithMethodToFire.run().

Here's a very simple example.

public class SomethingThatShouldHappenInAThread {
     private TaskExecutor taskExecutor;
     private ClassWithMethodToFire classWithMethodToFire;

     public SomethingThatShouldHappenInAThread(TaskExecutor taskExecutor,
                                               ClassWithMethodToFire classWithMethodToFire) {
          this.taskExecutor = taskExecutor;
          this.classWithMethodToFire = classWithMethodToFire;
     }

     public void fire(final SomeParameterClass parameter) {
          taskExecutor.execute( new Runnable() {
               public void run() {
                    classWithMethodToFire.doSomething( parameter );
               }
          });
     }
}

And here are the Spring beans:

<bean name="somethingThatShouldHappenInAThread" class="package.name.SomethingThatShouldHappenInAThread">
     <constructor-arg type="org.springframework.core.task.TaskExecutor" ref="taskExecutor" />
     <constructor-arg type="package.name.ClassWithMethodToFire" ref="classWithMethodToFireBean"/>
</bean>

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
     <property name="corePoolSize" value="5" />
     <property name="maxPoolSize" value="10" />
     <property name="queueCapacity" value="25" />
</bean>
Jacob Mattison
  • 50,258
  • 9
  • 107
  • 126
  • I think my problem is thinking this is more complex then it is. I saw http://docs.huihoo.com/javadoc/spring/2.0/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html#createQueue(int) and I assumed a ThreadPoolTaskExecutor had a built in queuing mechanism. – James McMahon May 12 '09 at 14:21
  • Maybe I wasn't mistaken, what is queueCapacity for? I still feel like I am missing something here. – James McMahon May 12 '09 at 14:35
  • 12
    If the queue capacity is greater than 0, it creates a queue, so that the tasks that are fired by a particular TaskExecutor can wait until a thread is available from the pool. The capacity indicates how many spaces are in the queue. If the queue fills up, the executor will block (i.e. the execute method won't return until a space opens up). Here's the doc on the queue: http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/LinkedBlockingQueue.html – Jacob Mattison May 12 '09 at 15:13
  • But you don't modify the queue externally, it is all managed by the TaskExecutor implementation right? I think I get it now. I was thinking you could add all the items you wanted to a queue and then pass it in to the TaskExecutor and have that execute it for you. – James McMahon May 12 '09 at 15:16
  • 1
    Ah. No, it's all handled for you, as you say. You just call execute over and over and the tasks get queued if necessary. – Jacob Mattison May 12 '09 at 17:30
  • Though the documentation for corePoolSize, maxPoolSize, queueCapacity could be better. I am not sure I understand what that is controlling. – James McMahon May 12 '09 at 18:21
  • 1
    Wait, got it, just need to look at the documentation for the Java clases that the Spring classes are based on. http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html – James McMahon May 12 '09 at 18:36
  • 2
    To ensure blocking on full queue/pool, you need to set `rejectedExecutionHandler` to `java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy`. Default handler, AbortPolicy, (http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.html#setRejectedExecutionHandler%28java.util.concurrent.RejectedExecutionHandler%29) aborts tasks instead of block the caller. – mrzasa Jan 11 '12 at 15:21
  • About blocking the caller : http://www.jroller.com/ndpar/entry/taskexecutor_blocking_queue – JBA May 01 '14 at 08:41