My initial plan was to switch from a plain ThreadPoolExecutor and Timers to a ScheduledExecutorService. Once done, I would write a GAE-specific, single-threaded version of that class tries to mimic the intended behaviour as good as possible.
The problem is that the ScheduledExecutorService class is a fixed-size thread pool using an unbounded work queue, which just doesn't work in ESXX. Consider this simple example:
It creates a fixed-size thread pool, and adds and waits for a job. The job, in turn, adds and waits for another job. The problem is that there are no worker threads left, so the second job is just queued and never executed, resulting in a deadlock.
import java.util.concurrent.*;
class STPEDeadlock {
public static void main(String[] args) {
final ExecutorService exe =
new ScheduledThreadPoolExecutor(1, new ThreadPoolExecutor.CallerRunsPolicy());
System.out.println(Thread.currentThread() + ": Submitting job 1");
Future j1 = exe.submit(new Runnable() {
@Override public void run() {
System.out.println(Thread.currentThread() + ": Submitting job 2");
Future j2 = exe.submit(new Runnable() {
@Override public void run() {
System.out.println(Thread.currentThread() + ": Running job 2");
}
});
try {
System.out.println(Thread.currentThread() + ": Waiting for job 2");
j2.get();
}
catch (Throwable t) {
t.printStackTrace();
}
}
});
try {
System.out.println(Thread.currentThread() + ": Waiting for job 1");
j1.get();
}
catch (Throwable t) {
t.printStackTrace();
}
System.out.println(Thread.currentThread() + ": All done");
exe.shutdown();
}
}
If you replace the executor with
final ExecutorService exe = new ThreadPoolExecutor(1, 1,then all is fine again. This is the fixed-size executor configuration I use in ESXX. Unfortunately, there is no way to configure a ScheduledExecutorService to match this behavior.
0L, TimeUnit.MILLISECONDS,
new SynchronousQueue(),
new ThreadPoolExecutor.CallerRunsPolicy());
What were the Sun developers thinking??
No comments:
Post a Comment