ExecutorService和ThreadPoolExecutor

文章译自:http://tutorials.jenkov.com/java-util-concurrent/index.html 
抽空翻译了一下这个教程的文章,后面会陆续放出,如有不妥,请批评指正。 
转自请注明出处。

ExecutorService

Java.util.concurrent.ExecutorService接口代表一种异步执行机制,它能够在后台执行任务。因此ExecutorService与thread pool是非常相似的。事实上,在java.util.package包中ExecutorService的具体实现就是一个线程池的具体实现。

ExcutorService 例子

下面是一个简单的例子

ExecutorService executorService = Executors.newFixedThreadPool(10);

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

executorService.shutdown();

首先,通过newFixedThreadPool()工厂方法创建一个ExecutorService的实例。这个方法创建了一个可以有10个线程执行任务的线程池。

第二,Runnable接口的匿名实现类作为参数被传递给execute()方法。Runable将会被ExecutorService中的一个线程来执行。

任务委托(Task Delegation)

下面的图片说明了一个线程委托一个任务给ExecutorService进行异步执行: 
这里写图片描述 
一旦,线程委托任务给ExecutorService,线程会独立任务的执行而继续自己之后的操作。

ExcutorService的使用说明

下面是委托任务给ExecutorService的一些不同的方式:

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

下面来逐个看看这些方法。

  • execute(Runnable)

execute(Runnable) 方法接受一个java.lang.Runable对象的实例,并异步执行之。下面是一个使用ExecutorService执行Runnable的例子:

ExecutorService executorService = Executors.newSingleThreadExecutor();

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

executorService.shutdown();

这种方式不能获得Runnable执行的结果,如果有这种需要,你将要使用Callable。


  • submit(Runnable)

submit(Runnable) 方法也接收一个Runnable接口的具体实现,并返回一个Future对象。Future对象可以用来检测Runable是否执行完成。

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

submit(Callable)方法与submit(Runnable)方法相似,除了接收的参数有所不同。Callable实例非常类似于Runnable,不同的是call方法可以返回一个结果,Runnable.run()方法不能返回一个结果(因为是void类型),就算线程执行完了,成功了future.get()也只是得到null

可以通过submit(Callable)方法返回的Future对象获取Callable的结果。下面是一个使用Callable的例子:

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对象或者Callable的子接口实例的集合作为参数,这个方法不会返回Future,但会返回集合中某一个Callable的结果。你不能确定你得到是哪个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集合中一个Callable任务返回的结果。我尝试执行了多次,结果是变化的。有时候是“Task1”,有时候是“Task 2”等。

  • invokeAll(…)

invokeAll()接收一个Callable对象的集合作为参数,该方法会调用你传给他的集合中的所有Callable对象。Invoke()会返回一个Future对象的列表,通过这个列表你可以获取每一个Callable执行的结果。

一个任务可能会因为一个异常而结束,因此这时任务并不是真正意义上执行成功了。这在Future上是没有办法来判断的。

处理一个任务的容器(collection),并返回一个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();

ExecutorService Shutdown

当你是使用完ExecutorService后,你应该关闭它,使得线程不能持续运行。例如,你的应用程序从main()方法开始并且你的主线程退出应用程序,这时如果存在激活状态的ExecutorService,你的应用程序将仍然会保持运行。ExecutorService中激活的线程会阻止JVM关闭。

为了终止ExecutorService中的线程,你需要调用shutdown()方法。ExecutorService不会立即关闭,但是它也不会接受新的任务,直到它里面的所有线程都执行完毕,ExecutorService才会关闭。所有提交到ExecutorService中的任务会在调用shutdown()方法之前被执行。

如果你想立即关闭ExecutorService,你可以调用shutdownNow()方法。这将会尝试立即停止所有正在执行的任务,并且忽略所有提交的但未被处理的任务。对于正在执行的任务是不能确定的,也许它们停止了,也行它们执行直到结束。

ThreadPoolExecutor

Java.util.concurrent.ThreadPoolExecutor类是ExecutorSerivce接口的具体实现。ThreadPoolExecutor使用线程池中的一个线程来执行给定的任务(Runnable或者Runnable)。

ThreadPoolExecutor内部的线程池包含不定数量的线程。池中线程的数量由下面的这些变量决定:

  • corePoolSize
  • maximumPoolSize

当一个任务委托给线程池执行,此时如果池线程中线程数少于corePoolSize,即使池中有空闲的线程,线程池中也会创建一个新的线程。

如果任务队列是满的,corePoolSize个线程或者更多的且少于maximumPoolSize的线程正在运行,也会创建一个新的线程来执行任务。

下面图释ThreadPoolExecutor这种原理: 
这里写图片描述

创建ThreadPoolExecutor

ThreadPoolExecutor有多种构造函数。例如:

int  corePoolSize  =    5;
int  maxPoolSize   =   10;
long keepAliveTime = 5000;

ExecutorService threadPoolExecutor =
        new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
                );

除非你需要显示的给ThreadPoolExecutor指定这些参数,通常使用java.util.concurrent.Executor类中的工厂方法来创建实例。


  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ExecutorServiceThreadPoolExecutor都是Java中用于管理线程池的接口和类,它们之间有一些区别。 ExecutorService是一个接口,定义了一组管理线程池的方法,比如提交任务、关闭线程池等。它继承自Executor接口,并扩展了一些新的方法。 ThreadPoolExecutorExecutorService接口的实现类,是Java提供的默认线程池实现。它是一个具体的线程池实现,可以直接使用或者通过工厂方法创建。ThreadPoolExecutor提供了更多的参数和配置选项,可以根据具体需求进行灵活的配置。 区别主要体现在以下几点: 1. 构造方式:ExecutorService可以通过Executors类中的工厂方法来创建,默认使用ThreadPoolExecutor实现。而ThreadPoolExecutor可以直接通过构造方法创建。 2. 灵活性:ThreadPoolExecutor提供了更多的参数和配置选项,可以进行更细粒度的线程池配置,比如核心线程数、最大线程数、线程空闲时间等。而ExecutorService提供的方法较为简单,没有这么多配置选项。 3. 扩展性:由于ExecutorService是一个接口,可以通过继承或实现该接口来扩展自定义的线程池实现。而ThreadPoolExecutor是一个具体的实现类,在可配置的基础上更为灵活,但无法直接扩展。 总结起来,ExecutorService是一个接口,提供了管理线程池的方法;而ThreadPoolExecutorExecutorService的实现类,提供了更多的参数和配置选项,可以更灵活地配置线程池。在大多数情况下,我们可以直接使用ExecutorService来管理线程池,而在需要更高度的可配置性时,可以使用ThreadPoolExecutor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值