上一节中讲到了ExecutorService中有一些管理Thread的方法
execute(Runnable)
submit(Runnable)
submit(Callable)
invokeAny(...)
invokeAll(...)
这个方法使用的参数是 java.lang.Runnable
包中的对象,调用这个方法之后将会异步执行runnable
。
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();
通过工厂构建一个ExecutorService实例,然后执行 自定义的Runnable
,这个方法是没有返回值的,如果你想得到一个返回值,可以使用 Callable
对象替代Runnable
(后面会讲到)
这个方法同execute(Runnable)
一样,都是异步执行一个task,但是submit
方法是有返回值的,它返回一个Future
对象,通过这个对象,可以检查这个Runnable
实例是否执行完成。
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
future.get(); //returns null if the task has finished correctly.
//这个方法返回的是这个任务结束(不一定正常结束)的结果,必要的时候这个方法会等待结果出来。
//如果返回值为null,则表明这个任务已经正常的执行完毕。
这个方法的参数和submit(Runnable)不同。
Runnable和Callable的区别是,Runnable中onRun()方法是没有返回值的,而Callable中的call()方法是有返回值的。
call()方法的返回值要如何得到呢? 可以通过 submit(Callable)方法的返回值 Future对象得到。
举例:
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});
System.out.println("future.get() = " + future.get());
控制台打印的结果如下:
Asynchronous Callable
future.get() = Callable Result
这个方法接收的参数是 Callable(或者Callable的实现类)对象的集合
而且这个方法并不会返回 Future对象,而是返回集合中某个Callable对象的return的值,具体是哪一个呢? 答案是:无法确认(这个跟他的机制有关),但是可以确认的是这个Callable对象是完成了的。
机制:如果 集合中的某个task,完成了(或者抛出异常),那么集合中剩余的task将全部会被取消,不会得到执行。
下面是例子:
ExecutorService executorService = Executors.newSingleThreadExecutor();
SetString>> callables = new HashSetString>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();
这个打印的结果将会是集合中的某一个Callable对象中call()方法返回的值,笔者(不是译者)尝试过多次,打印的结果是不同的, 有时候是 Task 1
有时候会是 Task 2
等。
参数:这个方法接收的参数是 Callable(或者Callable的实现类)对象的集合
这个方法将会调用 集合中全部的 Callable对象。
返回值:将返回一个包含Future对象的List集合,你可以通过 list中的future对象来获取,callable的返回值。
需要注意的是task结束的时候可能是因为 异常(没有正常结束),所以这个task可能并没有成功。但是通过future对象是无法判断,task 是否成功执行 结束,还是 异常 结束。
ExecutorService executorService = Executors.newSingleThreadExecutor();
SetString>> callables = new HashSetString>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
ListString>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
executorService.shutdown();
当你使用ExecutorService
的时候,你应该记得关闭它,这样这些被管理的线程才会停止运行。
举例:如果你的应用通过main()方法启动,并且你的 应用中存在一个 激活的 ExecutorService,那么即使你的main thread
(main线程)已经退出了,这个应用依然会在后台运行。 原因: ExecutorService
中的活跃线程,防止了jvm关闭ExecutorService
。
结论:jvm是可能无法关闭ExecutorService
的,如果某些情况下,你不希望ExecutorService
在后台不受控制的执行,那你在必要的时候 需要手动调用 ExecutorService
中的shutdown
方法。
通过调用ExecutorService中的shutdown方法可以终止该ExecutorService中的线程,但是ExecutorService并不会立即关闭,但是ExecutorService已经不会再接收新的task了,等到所有的thread完成各自的task,那么这个ExecutorService就会关闭。并且所有task中的结果 会在shutdown方法执行之前 submit(提交),都是已经执行完成了的。并不会存在没有的执行的task。
结论:手动调用shutdown并不会立即关闭ExecutorService,而是等待ExecutorService中所有的任务完成,并且提交之后,才会关闭的。(所以手动调用shotdown方法,可以不必担心存在剩余任务没有执行的情况)
如果你想立即关闭一个ExecutorService,你可以调用shutdownNow方法来实现。调用这个方法,ExecutorService将会”尝试着“关闭所有正在执行的task,这个关闭的过程会自动跳过那些已经submit的task(节省性能)。但是 对于那些正在 执行的task,并不能保证他们就一定会直接停止执行,或许他们会暂停,或许会执行直到完成,但是ExecutorService会尽力关闭所有正在运行的task。
参考链接:链接1