ExecutorService表述了异步执行的机制,并且可以让任务在后台执行。一个ExecutorService实例就是一个线程池。
ExecutorService实例
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runable(){
@Override
public void run(){
System.out.println("Asynchronus task");
}
});
executorService.shutdown();
Note: 首先通过newFixedThreadPool()工厂方法创建一个ExecutorService实例。上述代码创建了一个可以容纳10个线程任务的线程池。
其次,向execute()方法中传递一个异步的runnable接口实现,这样做会让ExecutorService中的某一个线程执行这个Runnable线程。
ExecutorService的实现
创建ExecutorService是采用Executors工厂方法来创建的。以下有几个例子,代表创建不同的线程池
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
//创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
//创建一个定长线程池,支持定时及周期性任务执行
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
任务委托
我们来展示一个线程的任务委托异步执行的ExecutorService的示意图。
[图片上传失败...(image-7aedc5-1577719003067)]
一旦线程把任务委托给ExecutorService,那么该线程就会继续执行与运行任务无关的其他任务
ExecutorService使用方法
-
execute(Runnable)
接收一个runable对象作为参数,并且以异步的方式执行它。请看上面实例
-
submit(Runnable)
接收一个sunable对象作为参数,但是会返回一个Future对象。这个Future对象可以用于判断Runable是否结束执行。如下举例:
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
//如果任务结束执行则返回 null
System.out.println("future.get()=" + future.get()); </pre>
3. submit(Callable)
和方法submit(Runable)类似。区别在于他们接收的参数类型不同。Callable的call方法可以返回一个结果,Runable.run()则不能返回结果。举例说明:
```java
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());
-
invokeAny(...)
接收一个包含Callbable对象的集合作为参数。调用该方法会返回集合中的某一个Callable对象的结果,但无法保证调用之后返回的结果是哪一个Callable对象。如果一个任务执行完毕,或者抛出异常,方法会取消其他的Callable执行。举例说明:
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();
-
invokeAll(...)
调用存在于参数集合中的所有 Callable 对象,并且返回壹個包含 Future 对象的集合,你可以通过这個返回的集合来管理每個 Callable 的执行结果。需要注意的是,任务有可能因为异常而导致运行结束,所以它可能并不是真的成功运行了。举例说明:
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.invokeAll(callables);
System.out.println("result = " + result);
executorService.shutdown(); </pre>
ExecutorService 关闭
当使用完ExecutorService服务后,我们要关闭它。这样才能保证线程不会继续运行。如果没有关闭掉ExecutorService会导致程序继续保持运行状态,也会导致该进程无法被Java虚拟机关闭,出现可能的内存泄露情况。所以为了关闭ExecutorService中的线程,可以调用shutdown方法。这个方法不会马上关闭线程,而是不再接收新的任务。等到所有的线程都结束执行当前的任务,ExecutorService才会真的关闭。如果希望马上关闭Executorservice,可以调用shutdownNow()。
网友评论