Java ExecutorService

时间:2020-01-09 10:36:26  来源:igfitidea点击:

Java ExecutorService接口java.util.concurrent.ExecutorService表示一种异步执行机制,该机制能够在后台并发执行任务。在此Java ExecutorService教程中,我将说明如何创建ExecutorService,如何向其提交执行任务,如何查看这些任务的结果以及在需要时如何再次关闭ExecutorService。 。

Java ExecutorService视频教程

如果我们喜欢视频,我在这里有JavaExcecutorService的视频介绍:

任务委托

一旦线程将任务委托给ExecutorService,线程将继续自己的执行,而与该任务的执行无关。然后,ExecutorService并发执行任务,而与提交任务的线程无关。

Java ExecutorService示例

在我们深入了解ExecutorService之前,让我们看一个简单的示例。这是一个简单的JavaExecutorService示例:

ExecutorService executorService = Executors.newFixedThreadPool(10);

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

executorService.shutdown();

首先使用ExecutorsnewFixedThreadPool()工厂方法创建一个ExecutorService。这将创建一个具有10个执行任务的线程的线程池。

其次,将Runnable接口的匿名实现传递给execute()方法。这将导致" Runnable"由" ExecutorService"中的线程之一执行。

在本教程中,我们还将看到更多有关如何使用ExecutorService的示例。这个例子只是让我们快速了解如何使用ExecutorService在后台执行任务。

Java ExecutorService实现

Java的ExecutorService与线程池非常相似。实际上,存在于java.util.concurrent包中的ExecutorService接口的实现是线程池实现。如果我们想了解如何在内部实现ExecutorService接口,请阅读上述教程。

由于ExecutorService是一个接口,因此我们需要对其实现进行任何使用。 ExecutorService在java.util.concurrent包中具有以下实现:

  • 线程池执行器
  • ScheduledThreadPoolExecutor

创建一个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(...)

在以下各节中,我将介绍每种方法。

执行可运行

Java ExecutorServiceexecute(Runnable)方法采用一个java.lang.Runnable对象,并异步执行它。这是一个用ExecutorService执行Runnable`的例子:

ExecutorService executorService = Executors.newSingleThreadExecutor();

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

executorService.shutdown();

如有必要,无法获得已执行的" Runnable"的结果。为此,我们将必须使用"可调用"(在以下各节中进行说明)。

提交可运行

Java的ExecutorService的submit(Runnable)方法也采用了Runnable的实现,但是返回了一个Future对象。这个Future对象可以用来检查Runnable是否完成执行。

这是一个JavaExecutorService``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完成的时间。

提交可致电

Java ExecutorService的submit(Callable)方法类似于submit(Runnable)方法,只是它采用Java Callable而不是Runnable。稍后将解释"可调用"与"可运行"之间的精确区别。

可通过submit(Callable)方法返回的Java Future对象获得Callable的结果。这是一个ExecutorService``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"将被取消。

这是一个代码示例:

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"之一返回的对象。我尝试运行了几次,结果改变了。有时是"任务1",有时是"任务2",等等。

invokeAll()

invokeAll()方法调用作为参数传递的集合中传递给它的所有Callable对象。 invokeAll()返回一个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";
    }
});

List<Future<String>> futures = executorService.invokeAll(callables);

for(Future<String> future : futures){
    System.out.println("future.get = " + future.get());
}

executorService.shutdown();

可运行与可调用

"可运行"界面与"可调用"界面非常相似。这两个接口都表示可以由线程或者ExecutorService并发执行的任务。这两个接口只有一个方法。不过," Callable"和" Runnable"接口之间只有一个小区别。当我们看到接口声明时,将更容易看到" Runnable"和" Callable"接口之间的区别。

首先是" Runnable"接口声明:

public interface Runnable {
    public void run();
}

这是Callable接口声明:

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

Runnable的run()方法和Callable的call()方法之间的主要区别是call()方法可以从方法调用中返回Object。 call()和run()之间的另一个区别是call()可以引发异常,而run()不能引发异常(RuntimeException的未经检查的异常子类除外)。

如果需要向Java ExecutorService提交任务,并且需要任务的结果,则需要使任务实现Callable接口。否则,任务只能实现" Runnable"接口。

取消任务

我们可以通过在提交任务时返回的" Future"上调用" cancel()"方法来取消提交给Java ExecutorService的任务(" Runnable"或者" Callable")。仅当任务尚未开始执行时,才可以取消任务。这是通过调用Future.cancel()方法取消任务的示例:

future.cancel();

执行器服务关闭

使用完JavaExecutorService后,应将其关闭,这样线程就不会继续运行。如果应用程序是通过main()方法启动的,而主线程退出了应用程序,那么如果应用程序中有活动的ExexutorService,则该应用程序将继续运行。该ExecutorService中的活动线程可防止JVM关闭。

关掉()

要终止ExecutorService内部的线程,请调用其Shutdown()方法。 ExecutorService不会立即关闭,但是将不再接受新任务,并且一旦所有线程都完成了当前任务,ExecutorService就会关闭。执行所有在调用Shutdown()之前提交给ExecutorService的任务。这是执行JavaExecutorService关闭的示例:

executorService.shutdown();

shutdownNow()

如果我们想立即关闭ExecutorService,可以调用shutdownNow()方法。这将尝试立即停止所有正在执行的任务,并跳过所有已提交但未处理的任务。不能保证执行任务。也许他们停止了,也许执行到了最后。这是尽力而为的尝试。这是调用ExecutorService``shutdownNow的示例:

executorService.shutdownNow();

awaitTermination()

ExecutorService的awaitTermination()方法将阻塞调用它的线程,直到ExecutorService完全关闭或者发生给定的超时为止。通常在调用" shutdown()"或者" shutdownNow()"之后调用" awaitTermination()"方法。这是调用ExecutorService``awaitTermination()的示例:

executorService.shutdown();

executorService.awaitTermination();