JAVA并发-ExecutorService
mhr18 2024-12-27 16:20 20 浏览 0 评论
ExecutorService接口, java.util.concurrent.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 接口的类,这会导致Runnable由ExecutorService中的一个线程执行。
本文将会有更多样子来说明怎么使用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
- 上一篇:并发编程常见问题
- 下一篇:Project Loom:了解新的 Java 并发模型
相关推荐
- Java培训机构,你选对了吗?(java培训机构官网)
-
如今IT行业发展迅速,不仅是大学生,甚至有些在职的员工都想学习java开发,需求量的扩大,薪资必定增长,这也是更多人选择java开发的主要原因。不过对于没有基础的学员来说,java技术不是一两天就能...
- 产品经理MacBook软件清单-20个实用软件
-
三年前开始使用MacBookPro,从此再也不想用Windows电脑了,作为生产工具,MacBook可以说是非常胜任。作为产品经理,值得拥有一台MacBook。MacBook是工作平台,要发挥更大作...
- RAD Studio(Delphi) 本月隆重推出新的版本12.3
-
#在头条记录我的2025#自2024年9月,推出Delphi12.2版本后,本月隆重推出新的版本12.3,RADStudio12.3,包含了Delphi12.3和C++builder12.3最...
- 图解Java垃圾回收机制,写得非常好
-
什么是自动垃圾回收?自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用...
- Centos7 初始化硬盘分区、挂载(针对2T以上)添加磁盘到卷
-
1、通过命令fdisk-l查看硬盘信息:#fdisk-l,发现硬盘为/dev/sdb大小4T。2、如果此硬盘以前有过分区,则先对磁盘格式化。命令:mkfs.文件系统格式-f/dev/sdb...
- 半虚拟化如何提高服务器性能(虚拟化 半虚拟化)
-
半虚拟化是一种重新编译客户机操作系统(OS)将其安装在虚拟机(VM)上的一种虚拟化类型,并在主机操作系统(OS)运行的管理程序上运行。与传统的完全虚拟化相比,半虚拟化可以减少开销,并提高系统性能。虚...
- HashMap底层实现原理以及线程安全实现
-
HashMap底层实现原理数据结构:HashMap的底层实现原理主要依赖于数组+链表+红黑树的结构。1、数组:HashMap最底层是一个数组,称为table,它存放着键值对。2、链...
- long和double类型操作的非原子性探究
-
前言“深入java虚拟机”中提到,int等不大于32位的基本类型的操作都是原子操作,但是某些jvm对long和double类型的操作并不是原子操作,这样就会造成错误数据的出现。其实这里的某些jvm是指...
- 数据库DELETE 语句,还保存原有的磁盘空间
-
MySQL和Oracle的DELETE语句与数据存储MySQL的DELETE操作当你在MySQL中执行DELETE语句时:逻辑删除:数据从表中标记为删除,不再可见于查询结果物理...
- 线程池—ThreadPoolExecutor详解(线程池实战)
-
一、ThreadPoolExecutor简介在juc-executors框架概述的章节中,我们已经简要介绍过ThreadPoolExecutor了,通过Executors工厂,用户可以创建自己需要的执...
- navicat如何使用orcale(详细步骤)
-
前言:看过我昨天文章的同鞋都知道最近接手另一个国企项目,数据库用的是orcale。实话实说,也有快三年没用过orcale数据库了。这期间问题不断,因为orcale日渐消沉,网上资料也是真真假假,难辨虚...
- 你的程序是不是慢吞吞?GraalVM来帮你飞起来性能提升秘籍大公开
-
各位IT圈内外的朋友们,大家好!我是你们的老朋友,头条上的IT技术博主。不知道你们有没有这样的经历:打开一个软件,半天没反应;点开一个网站,图片刷不出来;或者玩个游戏,卡顿得想砸电脑?是不是特别上火?...
- 大数据正当时,理解这几个术语很重要
-
目前,大数据的流行程度远超于我们的想象,无论是在云计算、物联网还是在人工智能领域都离不开大数据的支撑。那么大数据领域里有哪些基本概念或技术术语呢?今天我们就来聊聊那些避不开的大数据技术术语,梳理并...
- 秒懂列式数据库和行式数据库(列式数据库的特点)
-
行式数据库(Row-Based)数据按行存储,常见的行式数据库有Mysql,DB2,Oracle,Sql-server等;列数据库(Column-Based)数据存储方式按列存储,常见的列数据库有Hb...
- AMD发布ROCm 6.4更新:带来了多项底层改进,但仍不支持RDNA 4
-
AMD宣布,对ROCm软件栈进行了更新,推出了新的迭代版本ROCm6.4。这一新版本里,AMD带来了多项底层改进,包括更新改进了ROCm的用户空间库和AMDKFD内核驱动程序之间的兼容性,使其更容易...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)