Tuesday, August 26, 2008

Why doesn't an executor reuse a thread after completing your task?

This could happen if your task throws a RuntimeException.. then the Java Executor will not reuse that thread and would create a new thread. Consider the following example, if you comment the line "throw new RuntimeException("Runtime");" you will get the following output:

This is some thread : TG-ID-1
This is some thread : TG-ID-2
...
This is some thread : TG-ID-20
This is some thread : TG-ID-20
This is some thread : TG-ID-20
This is some thread : TG-ID-20
...
...
This is some thread : TG-ID-20
..
This is some thread : TG-ID-2
This is some thread : TG-ID-1

But if you leave the RuntimeException, your outpur will be:
This is some thread : TG-ID-1
...
This is some thread : TG-ID-71
This is some thread : TG-ID-72
This is some thread : TG-ID-73
...
etc..


import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class TestExecutor {

public static void main(String[] args) {
new TestExecutor().test();
}

private void test() {
BlockingQueue blockingQueue = new LinkedBlockingQueue();
Executor executor = new ThreadPoolExecutor(
20, 100, 5,
TimeUnit.SECONDS,
blockingQueue,
new NativeThreadFactory(new ThreadGroup("My-T-grp"), "TG-ID"));

for (int i=0; i<100; i++) {
executor.execute(new Runnable() {
public void run() {
System.out.println("This is some thread : " + Thread.currentThread().getName());
throw new RuntimeException("Runtime");
}
});
}
}


public class NativeThreadFactory implements
ThreadFactory {

final ThreadGroup group;
final AtomicInteger count;
final String namePrefix;

public NativeThreadFactory(final ThreadGroup group, final String namePrefix) {
super();
this.count = new AtomicInteger(1);
this.group = group;
this.namePrefix = namePrefix;
}

public Thread newThread(final Runnable runnable) {
StringBuffer buffer = new StringBuffer();
buffer.append(this.namePrefix);
buffer.append('-');
buffer.append(this.count.getAndIncrement());
Thread t = new Thread(group, runnable, buffer.toString(), 0);
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}

}
}