本文主要是介绍ExecutorService引发的血案(二)ExecutorService使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
上一节中讲到了ExecutorService中有一些管理Thread的方法
execute(Runnable)
submit(Runnable)
submit(Callable)
invokeAny(...)
invokeAll(...)
execute(Runnable)
这个方法使用的参数是 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
(后面会讲到)
submit(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(Callable)
这个方法的参数和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
invokeAny()
这个方法接收的参数是 Callable(或者Callable的实现类)对象的集合
而且这个方法并不会返回 Future对象,而是返回集合中某个Callable对象的return的值,具体是哪一个呢? 答案是:无法确认(这个跟他的机制有关),但是可以确认的是这个Callable对象是完成了的。
机制:如果 集合中的某个task,完成了(或者抛出异常),那么集合中剩余的task将全部会被取消,不会得到执行。
下面是例子:
ExecutorService executorService = Executors.newSingleThreadExecutor();Set<Callable<String>> callables = new HashSet<Callable<String>>();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
等。
invokeAll()
参数:这个方法接收的参数是 Callable(或者Callable的实现类)对象的集合
这个方法将会调用 集合中全部的 Callable对象。
返回值:将返回一个包含Future对象的List集合,你可以通过 list中的future对象来获取,callable的返回值。
需要注意的是task结束的时候可能是因为 异常(没有正常结束),所以这个task可能并没有成功。但是通过future对象是无法判断,task 是否成功执行 结束,还是 异常 结束。
ExecutorService executorService = Executors.newSingleThreadExecutor();Set<Callable<String>> callables = new HashSet<Callable<String>>();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";}
});List<Future<String>> futures = executorService.invokeAll(callables);for(Future<String> future : futures){System.out.println("future.get = " + future.get());
}executorService.shutdown();
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
这篇关于ExecutorService引发的血案(二)ExecutorService使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!