JAVA并发-ExecutorService

ExecutorService接口java.util.concurrent.ExecutorService, 代表一种可以在后台并发执行的异步执行机制。在这篇ExecutorService 文章中,将解释如何创建ExecutorService,怎么提交任务并执行,怎么获取这些任务的结果,怎么关闭 ExecutorService以及再次使用。

任务委托

下图说明了,线程将任务委托给ExecutorService 异步执行:

 

 

线程将任务委托给ExecutorService 异步执行

一旦线程将任务委托给ExecutorService,线程将独立于该任务的执行继续自己的执行。ExecutorService然后并发地执行任务,独立于提交任务的线程。

Java ExecutorService例子

在深入了解ExecutorService 之前,先看看一个简单的例子,下面是一个简单的ExecutorService例子:

ExecutorService executorService = Executors.newFixedThreadPool(10);

executorService.execute(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});

executorService.shutdown();

 

首先,用Executos newFixedThreadPool()工厂方法创建一个 ExecutorService ,创建固定10个线程任务的线程池。

其次,通过execute()加入了匿名实现了Runnable 接口的类,这会导致RunnableExecutorService中的一个线程执行。

本文将会有更多样子来说明怎么使用ExecutorService ,这个例子知识为了快速了解通过ExecutorService怎么在后台执行任务。

ExecutorService实现

ExecutorService非常类似于线程池。实际上, 目前在java.util.concurrent包中实现了ExecutorService接口的类同时也是线程池的实现类。

ExecutorService 是个接口,所以需要使用它的实现。 ExecutorService java.util.concurrent包中的实现 

 

创建 ExecutorService

怎么创建 ExecutorService取决于用它的哪个实现。当然也可以用Executors 工厂类创建ExecutorService  实例,下面是一些创建ExecutorService 的例子:

ExecutorService executorService1 = Executors.newSingleThreadExecutor();

ExecutorService executorService2 = Executors.newFixedThreadPool(10);

ExecutorService executorService3 = Executors.newScheduledThreadPool(10);

 

ExecutorService用法

下面是使用ExecutorService不同的方法委托任务执行:

  • execute(Runnable)
  • submit(Runnable)
  • submit(Callable)
  • invokeAny(...)
  • invokeAll(...)

下面会介绍这些方法。

执行Runnable

 ExecutorService execute(Runnable)方法需要一个java.lang.Runnable 对象, 并且异步执行,下面是通过ExecutorService执行 Runnable:

ExecutorService executorService = Executors.newSingleThreadExecutor();

executorService.execute(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});

executorService.shutdown();

 

这个方式不能获取到执行的结果,如果需要,有个用Callable  (下面会介绍)。

提交Runnable

ExecutorService submit(Runnable)方法同样需要  Runnabl的实现, 但是返回一个Future 对象, Future可以用来检查Runnable 是否执行完成,下面是ExecutorService submit() 例子:

Future future = executorService.submit(new Runnable() {
    public void run() {
        System.out.println("Asynchronous task");
    }
});

future.get();  //returns null if the task has finished correctly.

 

submit() 方法返回Java Future链接查看英文,后续翻译解释,下文同样,就不加说明了 对象,此对象可以检查Runnable  是否执行完毕。

提交Callable

 ExecutorService submit(Callable)方法和 submit(Runnable)方法比较相似,除了使用了 Java Callable 而不是 Runnable. Callable  Runnable的不同下文会介绍

 Callable的结果可以通过submit(Callable)方法返回的Java 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()

invokeAny()方法的参数是 Callable对象的集合或者子类对象, 执行这个方法不会返回Future, 返回会返回其中一个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();

 

这段代码打印了 Callable集合执行返回中的一个结果,我试了多次有时候打印"Task 1", 有时候打印 "Task 2"

invokeAll()

invokeAll()方法调用 Callable集合作为参数传递的所有可调用对象。invokeAll()返回通过执行每个Callable得到的

Future 对象列表。记住,每个完成的任务可能是因为抛异常,实际上并没有成功。没有办法通过Future 分辨两者的区别。

下面是代码:

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();

 

Runnable Callable

Runnable Callable非常相似,都代表了一个线程或者ExecutorSerivce可以并发放执行的任务,两个接口都只有一个方法,两者只有一个细小的差别,他们之间的区别可以通过接口定义看出来.

 Runnable接口:

public interface Runnable {
    public void run();
}

 

Callable 接口:

public interface Callable{
    public Object call() throws Exception;
}

 

主要区别是 Runnable run() Callable call()call() 可以返回 Object,另外不同是 call()可以 throw 一个 exception, run()却不能 (除了不受检查的RuntimeException以及其子类).

如果需要通过ExecutorService 提交任务并且能有返回的结果,那么需要实现Callable 接口,否则值只要实现Runnable 接口。

取消Task

可以通过调用ExecutorService  返回的Future的 cancel()取消一个提交到ExecutorService 的任务 (Runnable or Callable),只能取消还没开始执行的任务,下面是个例子

future.cancel();

 

ExecutorService Shutdown

使用完Executorservice之后,应该关闭它,这样线程就不会继续运行了。如果你的应用程序是通过main()方法启动的,并且你的主线程退出了你的应用程序,那么如果你的应用程序中有一个活动的ExexutorService,那么该应用程序将继续运行。ExecutorService 中的活动线程阻止JVM关闭此服务

shutdown()

终止ExecutorService 内部的线程可以调用shutdown()方法,ExecutorService 不会立即关闭,但是不再接受新的任务,一旦当前所有线程执行完毕,ExecutorService 关闭,在调用shutdown() 之前,所有提交到ExecutorService 的任务将被执行,下面看下代码:

executorService.shutdown();

 

shutdownNow()

如果想立即关闭ExecutorService ,可以调用 shutdownNow()方法,将试图立即关闭所有执行的任务,跳过所有已提交但未处理的任务,对于执行的任务没有任何保证,也许他们会停止,也许会执行到最后。这是一个最大的努力尝试。看下调用代码:

executorService.shutdownNow();

 

awaitTermination()

线程调用 ExecutorService awaitTermination()将阻塞,直到其他ExecutorService完全关闭,或者超时。

 awaitTermination()正常在调用  shutdown() 或者 shutdownNow()之后调用. 看下面代码:

executorService.shutdown();

executorService.awaitTermination();

 

参考:http://tutorials.jenkov.com/java-util-concurrent/executorservice.html

       https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值