I would make a fool out of myself if I tell you that util.concurrent APIs kicks cheetah's ass when the classes are available since 2004. However, there are some cool features which I would like to revisit. Concurrency experts, now is the time for you to close this window. All others, stay tight for the fun ride.java
Thou shall not forget your rootsless
Executor is the root interface with a single execute method. Anything that implements a Runnable interface can passed as a parameter. Silly Executor, however, has no support for Callable though.ide
Good news : ExecutorService interface, which extends Executor, adds support for Callable. Its implementation class is ThreadPoolExecutor.oop
I am going to pretend that the ScheduledExecutorService interface and its implementation class ScheduledThreadPoolExecutor does not exist as they just add scheduling capabilities on top of the ExecutorService and ThreadPoolExecutor. But remember this class when the powerful but boring java.util.Timer
is not enough and a full blown external scheduler is just too much.post
If you are new to concurrency or forgot the difference between Callable and Runnable, you might want to read up a little before reading further. A dummy guide is hereui
The ExecutorService.submit Facts :this
The three submit variants : code
Future submit(Callable task) <br> Future submit(Runnable task) <br> Future submit(Runnable task, T result)
The submit
method of the ExecutorService is overloaded and accepts either a Callable
or Runnable
.blog
Since the run
method of the Runnable returns void, it is no surprise that Future.get
always returns a null when the task is complete.three
Future<?> submit(Runnable task)
submit
method that accepts a Runnable
and a generic returns whatever you passed in as the second parameter as the result.<T> Future<T> submit(Runnable task, T result)
In fact, opening up the code (FutureTask
), you'll notice that the RunnableAdapter
top level nested class of Executors
simply holds the result and returns the same result after the run method is complete.
###爲什麼用ThreadPoolExecutor 的submit(runnable,T result)倒是能夠返回結果的呢??
static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T [More ...] call() { task.run(); return result; } }
In both the cases, if you would like to (you should !) terminate the program instead of your executor thread blocking the program and entering a busy loop, you should call the shutdown method as in
executorService.shutdown()
shutDown facts
You could imagine shutdown
as a half-closed door of a mall. No new customers will be let in but the existing customers can leave the mall once they are done.
To reiterate,
shutdown
is a polite method. It does not actually shut down the tasks in the pool immediately. It just says that no new tasks will be accepted.
Unless you are executing your tasks using invokeAll
, you would need to wait for all tasks in progress to complete. This is achieved by calling the awaitTermination
method.
(invokeAll and submit examples at the bottom of the post)
Once all the current tasks are done, the executor service shuts down.
If you are in need of an impolite, intruding method which doesn't care whether the current threads are done with their tasks, then shutdownNow is your guy. However, there's no guarantee that the method will shutdown the service on the dot but it is the closest you have to immediate shutdown.