ExecutorService的理解和使用

2019-12-30  本文已影响0人  极客匠

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使用方法

  1. execute(Runnable)

    接收一个runable对象作为参数,并且以异步的方式执行它。请看上面实例

  2. 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());
  1. 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(); 
  1. 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()。

上一篇 下一篇

猜你喜欢

热点阅读