Is it safe for a task (a Runnable
) being run by an Executor
to submit (execute()
) a task? Can it result in deadlock, if using any of the standard Java executors? Is there any particular configuration I should use, or avoid, if I want to prevent deadlock, for the standard executors? I'm guessing that submitting a task to a different executor is safe, but what about submitting the task to the executor running the original task?

- 46,613
- 43
- 151
- 237
-
See also http://stackoverflow.com/questions/1702386/is-threadpoolexecutor-thread-safe – Raedwald Apr 29 '14 at 15:16
3 Answers
If there is a deadlock, it will be created by conditions in your deployed runnables. The ExecutorService itself is just a reusable thread pool. It handles queueing runnables for execution. There should be no reason the ExecutorService itself would be deadlocked regardless of where the Runnables originated from.

- 3,396
- 1
- 19
- 26
Is it safe for a task (a Runnable) being run by an Executor to submit (execute()) a task?
Provided it doesn't create too many tasks as to overload the system, it is safe. e.g. if you have a task which creates two tasks and they create two tasks ...
Can it result in deadlock, if using any of the standard Java executors?
The Executors
are thread safe and the task is added to a queue.
Is there any particular configuration I should use, or avoid, if I want to prevent deadlock, for the standard executors?
You can create a ThreadPoolExecutor with one thread and a SynchronousQueue and this could block itself. But I wouldn't do that. ;)
I'm guessing that submitting a task to a different executor is safe, but what about submitting the task to the executor running the original task?
Provided you have any of the following, you won't have problem. Often you have all of these
- a growing queue
- the execute fail if it cannot be added i.e. don't block
- an expandable thread pool

- 525,659
- 79
- 751
- 1,130
If you call get on the future then you can surely deadlock, in simple example as below this might be obvious to spot but if you have some class hierarchy that hides executors usage then someone by mistake can introduce such bug.
class TestApp {
public static class MyCallable
implements Callable {
public Integer call() throws ExecutionException, InterruptedException {
Future<Integer> future = pool.submit(new MyCallable());
System.out.println("MyCallable: before get 2");
future.get(); // deadlocks here
System.out.println("MyCallable: after get 2");
return 0;
}
}
static ExecutorService pool = Executors.newSingleThreadExecutor();
public static void main(String [] args) throws ExecutionException, InterruptedException {
Future<Integer> future = pool.submit(new MyCallable());
System.out.println("MyCallable: before get 1");
future.get();
System.out.println("MyCallable: after get 1");
}
}
prints
MyCallable: before get 1
MyCallable: before get 2
MyCallable: before get 2
MyCallable: before get 2

- 48,511
- 9
- 79
- 100