java并发中ExecutorService的使用

ExecutorService是java中的一个异步执行的框架,通过使用ExecutorService可以方便的创建多线程执行环境。

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

创建ExecutorService

通常来说有两种方法来创建ExecutorService。

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

ExecutorService executor = Executors.newFixedThreadPool(10);

除了newFixedThreadPool方法之外,Executors还包含了很多创建ExecutorService的方法。

第二种方法是直接创建一个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()这几个方法来实现。

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的博客

java并发中ExecutorService的使用的更多相关文章

  1. java并发中的Synchronized关键词

    文章目录 为什么要同步 Synchronized关键词 Synchronized Instance Methods Synchronized Static Methods Synchronized B ...

  2. 深入浅出Java并发中的CountDownLatch

      1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...

  3. java并发中CountDownLatch的使用

    文章目录 主线程等待子线程全都结束之后再开始运行 等待所有线程都准备好再一起执行 停止CountdownLatch的await java并发中CountDownLatch的使用 在java并发中,控制 ...

  4. Java 并发工具包——ExecutorService常用线程池

    1. 执行器服务 ExecutorService java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务.因此一个 Executo ...

  5. Java并发中的CopyOnWrite容器

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  6. 一起来看看java并发中volatile关键字的神奇之处

    并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...

  7. Volatile 原理及使用,java并发中的可见性问题

    1.解决并发编程中的可见性问题 volatile 代表不使用cpu缓存,修改后的数据,将直接刷到内存中,被volatile修饰的变量,读取的时候,也是从内存中读取,不从cpu缓存中读取 上代码 // ...

  8. java并发中的Semaphore

    什么是Semaphore Semaphore可以控制某个资源可被同时访问的个数(locks和synchronized锁,在任何时刻只允许一个任务访问一个资源),通过acquire()获取一个许可,如果 ...

  9. java concurrent 中ExecutorService和CompletionService简单区别

    举个例子,现在需要执行10个任务,这些任务都是有返回值,并且需要使用10个线程同时执行.一般的做法就是创建ExecutorService线程池,pool大小10,每个任务实现Callable接口,然后 ...

随机推荐

  1. linux 之虚拟机的安装与介绍

    linux 零基础入门1.1linux介绍 操作系统用途: 管理硬件 驱动硬件 管理软件 分配资源1.2 linux的发展unix -> windows ->linuxlinux 免费 开 ...

  2. 面试刷题32:你对tomcat做了哪些性能调优?

    背景 java程序员的开发的java应用程序,一般都会选择使用tomcat发布,但是: 如何充分的掌控tomcat,并让它发挥最优性能呢? 这也是面试的热点问题,结合多年的工作实践,我是李福春,今天总 ...

  3. 并发——抽象队列同步器AQS的实现原理

    一.前言   这段时间在研究Java并发相关的内容,一段时间下来算是小有收获了.ReentrantLock是Java并发中的重要部分,所以也是我的首要研究对象,在学习它的过程中,我发现它是基于抽象队列 ...

  4. C9K Stackwise Virtual(一)

    一.SV技术基本说明 思科Catalyst9K平台的Stackwise Virtual技术是将两个物理的交换机虚拟成一个逻辑的实体(从网络控制层面和管理的角度来看),这两个交换机合二为一之后,将共享相 ...

  5. 【Linux】Linux(一)Linux常用命令

    一 命令行提示符 1.[root@localhost ~]# 当前登录用户@主机名:当前所在目录$ # 超级用户 $  普通用户 当前所在目录:~ 用户家目录 管理员 /root 普通用户 /home ...

  6. 【php】面向对象(四)

    知识点:ai一. a => abstract(抽象类) a) 抽象类的修饰符,修饰类和成员方法 b) 注意:被修饰的类不能被实例化,被修饰的方法不能有程序体 c) 如果某一个类使用abstrac ...

  7. 基于 mpvue 框架的小程序选择控件,支持单列,多列,联动

    最近在学着写mpvue小程序,在做选择控件时候遇到了点问题,按照微信小程序方法picker,很不方便! 在网上搜到一个很好用的组件下面给大家分享: 组件说明文档链接:https://go.ctolib ...

  8. 关于json语句的相关用法

    json语句: JSON 值可以是: 数字(整数或浮点数)字符串(在双引号中)逻辑值(true 或 false)数组(在中括号中)对象(在大括号中)null 对于json的的对象数组:var site ...

  9. 20175110 王礼博 exp4恶意代码分析

    目录 1.基础知识 2.系统运行监控 3.恶意软件分析 4.基础问题回答 5.实践总结与体会 1. 基础知识 1.1 恶意代码的概念与分类 定义:指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的 ...

  10. python3(十二)functional

    # 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数! # 变量可以指向函数 abs(-10) abs # <built-in function abs> ...