java并发中ExecutorService的使用

java并发中ExecutorService的使用java

ExecutorService是java中的一个异步执行的框架,经过使用ExecutorService能够方便的建立多线程执行环境。git

本文将会详细的讲解ExecutorService的具体使用。github

建立ExecutorService

一般来讲有两种方法来建立ExecutorService。多线程

第一种方式是使用Executors中的工厂类方法,例如:并发

ExecutorService executor = Executors.newFixedThreadPool(10);

除了newFixedThreadPool方法以外,Executors还包含了不少建立ExecutorService的方法。oracle

第二种方法是直接建立一个ExecutorService, 由于ExecutorService是一个interface,咱们须要实例化ExecutorService的一个实现。框架

这里咱们使用ThreadPoolExecutor来举例:异步

ExecutorService executorService =
            new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());

为ExecutorService分配Tasks

ExecutorService能够执行Runnable和Callable的task。其中Runnable是没有返回值的,而Callable是有返回值的。咱们分别看一下两种状况的使用:线程

Runnable runnableTask = () -> {
    try {
        TimeUnit.MILLISECONDS.sleep(300);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};
 
Callable<String> callableTask = () -> {
    TimeUnit.MILLISECONDS.sleep(300);
    return "Task's execution";
};

将task分配给ExecutorService,能够经过调用xecute(), submit(), invokeAny(), invokeAll()这几个方法来实现。code

execute() 返回值是void,他用来提交一个Runnable task。

executorService.execute(runnableTask);

submit() 返回值是Future,它能够提交Runnable task, 也能够提交Callable task。 提交Runnable的有两个方法:

<T> Future<T> submit(Runnable task, T result);

Future<?> submit(Runnable task);

第一个方法在返回传入的result。第二个方法返回null。

再看一下callable的使用:

Future<String> future = 
  executorService.submit(callableTask);

invokeAny() 将一个task列表传递给executorService,并返回其中的一个成功返回的结果。

String result = executorService.invokeAny(callableTasks);

invokeAll() 将一个task列表传递给executorService,并返回全部成功执行的结果:

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

关闭ExecutorService

若是ExecutorService中的任务运行完毕以后,ExecutorService不会自动关闭。它会等待接收新的任务。若是须要关闭ExecutorService, 咱们须要调用shutdown() 或者 shutdownNow() 方法。

shutdown() 会当即销毁ExecutorService,它会让ExecutorServic中止接收新的任务,并等待现有任务所有执行完毕再销毁。

executorService.shutdown();

shutdownNow()并不保证全部的任务都被执行完毕,它会返回一个未执行任务的列表:

List<Runnable> notExecutedTasks = executorService.shutdownNow();

oracle推荐的最佳关闭方法是和awaitTermination一块儿使用:

executorService.shutdown();
       try {
           if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
               executorService.shutdownNow();
           }
       } catch (InterruptedException e) {
           executorService.shutdownNow();
       }

先中止接收任务,而后再等待必定的时间让全部的任务都执行完毕,若是超过了给定的时间,则马上结束任务。

## Future

submit() 和 invokeAll() 都会返回Future对象。以前的文章咱们已经详细讲过了Future。 这里就只列举一下怎么使用:

Future<String> future = executorService.submit(callableTask);
String result = null;
try {
   result = future.get();
} catch (InterruptedException | ExecutionException e) {
   e.printStackTrace();
}

## ScheduledExecutorService

ScheduledExecutorService为咱们提供了定时执行任务的机制。

咱们这样建立ScheduledExecutorService:

ScheduledExecutorService executorService
                = Executors.newSingleThreadScheduledExecutor();

executorService的schedule方法,能够传入Runnable也能够传入Callable:

Future<String> future = executorService.schedule(() -> {
        // ...
        return "Hello world";
    }, 1, TimeUnit.SECONDS);
 
    ScheduledFuture<?> scheduledFuture = executorService.schedule(() -> {
        // ...
    }, 1, TimeUnit.SECONDS);

还有两个比较相近的方法:

scheduleAtFixedRate( Runnable command, long initialDelay, long period, TimeUnit unit )

scheduleWithFixedDelay( Runnable command, long initialDelay, long delay, TimeUnit unit )

二者的区别是前者的period是以任务开始时间来计算的,后者是以任务结束时间来计算。

ExecutorService和 Fork/Join

java 7 引入了Fork/Join框架。 那么二者的区别是什么呢?

ExecutorService能够由用户来本身控制生成的线程,提供了对线程更加细粒度的控制。而Fork/Join则是为了让任务更加快速的执行完毕。

本文的代码请参考https://github.com/ddean2009/learn-java-concurrency/tree/master/ExecutorService

更多教程请参考 flydean的博客

相关文章
相关标签/搜索