百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

JAVA并发-ExecutorService

mhr18 2024-12-27 16:20 14 浏览 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

相关推荐

2025最新指南:Quarkus整合Redisson,轻松玩转分布式锁!

分布式系统的高并发场景下,如何确保资源操作的原子性和一致性?Redisson作为Redis官方推荐的分布式锁方案,结合Quarkus的云原生特性,能实现高性能、低延迟的分布式锁管理。本文将从原理到实战...

Linux进程上下文切换过程context_switch详解

1前言1.1Linux的调度器组成2个调度器可以用两种方法来激活调度一种是直接的,比如进程打算睡眠或出于其他原因放弃CPU另一种是通过周期性的机制,以固定的频率运行,不时的检测是否有必要因此...

开发10年面试过上千人,在网易面试Java程序员,我最爱问这些问题

在网易当了3年的面试官,一般在面试Java程序员的时候,我主要会从这几个角度,去问这些问题,在这篇文章中,我会用我上一位面试过程来为大家总结,我面试的时候爱问的这些问题!有需要面试的小伙伴可以参考一下...

电影票务APP的“座位锁定”,Redis如何避免冲突?

现在买电影票,真是越来越方便了!再也不用提前老半天跑去电影院排队,在手机APP上动动手指,选好场次、挑好座位,在线支付,一气呵成。尤其是遇到热门大片,或者想抢个“皇帝位”(中间靠后视野好的位置),那个...

Serverless架构下,Redis的用武之地在哪里?

在云计算的演进浪潮中,Serverless(无服务器)架构无疑是一颗璀璨的明星。它将传统服务器的运维复杂性彻底“隐藏”起来,开发者只需关注核心业务逻辑,编写一个个独立的函数(Function-as-a...

高可用聊天系统设计方案(Hyperf实现)

一、系统架构设计1.分层架构图客户端↑↓HTTP/WSAPI网关层(Nginx+Keepalived)↑↓RPC业务服务集群↑↓数据层(MySQLClus...

大厂面试冲刺,Java“实战”问题三连,你碰到了哪个?

推荐学习全网首发!马士兵内部共享—1658页《Java面试突击核心讲》狂刷《Java权威面试指南(阿里版)》,冲击“金九银十”有望了Java“实战”问题三连Java“实战”面试题1:如果用mybati...

企业开发必备的6个Spring Cloud微服务开源项目

今天介绍六款比较热门的SpringCloud微服务项目,感兴趣的可以clone下来研究一下,相信对你学习微服务架构很有帮助。一、Cloud-Platform介绍Cloud-Platform是国内首个基...

系统架构设计方法论:系统演进的四重境界

在架构师面试中,设计能力的考察本质是验证候选人如何将混沌需求转化为可落地的技术方案。这不仅需要扎实的技术功底,更需要系统化的设计思维。以下四大步骤,既是架构设计的核心框架,也是技术决策的动态沙盘推演。...

跨浏览器共享Session信息方法总结

在不同浏览器之间共享Session信息需要克服浏览器间的隔离机制,常见解决方案如下:1.基于Token的跨浏览器传递实现方式:用户在主浏览器生成临时Token(如加密URL或二维码)。其他浏览器通过...

如何设计一套单点登录系统

一、介绍昨天介绍了API接口设计token鉴权方案,其实token鉴权最佳的实践场景就是在单点登录系统上。在企业发展初期,使用的后台管理系统还比较少,一个或者两个。以电商系统为例,在起步阶段,可能只有...

SpringBoot实现单点登录几种方案

前言:单点登录(SingleSign-On,SSO)是企业应用系统中常见的用户认证方案,它允许用户使用一组凭证访问多个相关但独立的系统,无需重复登录。基于Cookie-Session的传统SSO方案...

零基础小白如何学爬虫技术?看一遍就会的详细教程!

你以为爬虫需要精通编程、算法、网络协议才能入门?错了。作为零基础的小白,你完全可以在3周内学会主流网站的数据抓取,核心秘诀就两点:拆分具体目标+倒推式学习。与其纠结Python语法、HTTP协议这...

探秘Java中的分布式锁:优雅地协调分布式系统

探秘Java中的分布式锁:优雅地协调分布式系统在分布式系统的架构中,数据一致性是一个永恒的挑战。当我们需要在多个节点之间协调某些操作时,分布式锁便成为了一种不可或缺的工具。它就像一把钥匙,能够控制对共...

一文读懂 Spring Boot 3 分布式事务解决方案

在当今复杂的业务架构中,分布式事务处理是关键难题之一。随着业务规模的不断扩张,系统架构从单体逐渐演进为分布式,这就要求开发人员能够熟练掌握高效的分布式事务解决方案,以保障数据的一致性和业务的稳定性。今...

取消回复欢迎 发表评论: