Java 异步任务执行服务(一):基本概念和原理

1. 异步任务执行服务是什么意思?

答:

  • 线程 Thread 既表示要执行的任务(run() 方法),又表示执行的机制(start() 方法)
  • Java 并发包提供了一套框架,大大简化了执行异步任务所需的开发,这套框架引入了一个“执行服务”的概念
  • 执行服务将任务的提交和任务的执行相分离,“执行服务”封装了任务执行的细节,对于任务提交者而言,它可以关注于任务本身,如提交任务、获取结果、取消任务,而不需要关注任务执行的细节,如线程的创建、任务调度、线程关闭等。
  • 任务执行服务体现了并发异步开发中关注点分离的思想,使用者只需要通过 ExecutorService 提交任务,通过 Future 操作任务和结果即可,不需要关注线程创建和协调的细节

2. 任务执行服务涉及的基本接口有哪些?

答:

  • RunnableCallable:表示要执行的异步任务
  • ExecutorExecutorService:表示执行服务
  • Future:表示异步任务的结果

3. Runnable 和 Callable 的区别是什么?

答:二者都表示任务:

  • Runnable 没有返回结果,而 Callable 有返回结果
  • Runnable 不会抛出异常,而 Callable 会抛出异常

4. 怎样理解 Executor?

答:

  • Executor 表示最简单的执行服务
  • 定义:public interface Executor { void execute(Runnable command); }就是可以执行一个 Runnable,没有返回结果
  • 没有限定任务如何执行,可能是创建一个新线程,可能是复用线程池中的某个线程,也可能是在调用者线程中执行

5. 怎样理解 ExecutorService?

答:

  • ExecutorService 扩展了 Executor,定义了更多服务,基本方法有:

    public interface ExecutorService extends Executor {
        <T> Future<T> submit(Callable<T> task);
        <T> Future<T> submit(Runnable task, T result);
        Future<?> submit(Runnable task);
    
        void shutdown();
        List<Runnable> shutdownNow();
        boolean isShutdown();
        boolean isTerminated();
        boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
        <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
        <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
        <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
    }
    
  • 三个 submit() 都表示提交一个任务,返回值类型都是 Future,返回后,只是表示任务已提交,不代表已执行,通过 Future 可以查询异步任务的状态、获取最终结果、取消任务等对于 Callable,任务最终有个返回值,对于 Runnable 是没有返回值的。第二个提交 Runnable 的方法可以同时提供一个结果,在异步任务结束时返回;第三个方法异步任务的最终返回值为 null
  • 有两个关闭方法:shutdown()shutdownNow()。区别是,shutdown() 表示不再接受新任务,但已提交的任务会继续执行,即使任务还未开始执行;shutdownNow() 不仅不接受新任务,而且会终止已提交但尚未执行的任务,对于正在执行的任务,一般会调用线程的 interrupt() 方法尝试中断,不过,线程可能不响应中断,shutdownNow() 会返回已提交但尚未执行的任务列表
  • shutdown()shutdownNow() 不会阻塞等待,它们返回后不代表所有任务都已结束,不过 isShutdown() 方法会返回 true。调用者可以通过 awaitTermination() 等待所有任务结束,它可以限定等待的时间,如果超时前所有任务都结束了,即 isTerminated() 方法返回 true,则返回 true,否则返回 false
  • ExecutorService 有两组批量提交任务的方法:invokeAll()invokeAny(),它们都有两个版本,其中一个限定等待时间。
  • invokeAll() 方法等待所有任务完成,返回的 Future 列表中,每个 FutureisDone() 方法都返回 true,不过 isDone()true 不代表任务就执行成功了,可能是被取消了。invokeAll() 可以指定等待时间,如果超时后有的任务没完成,就会被取消。
  • 对于 invokeAny(),只要有一个任务在限时内成功返回了,它就会返回该任务的结果,其他任务会被取消;如果没有任务能在限时内成功返回,抛出 TimeoutException 异常;如果限时内所有任务都结束了,但都发生了异常,抛出 ExecutionException 异常。
  • 使用 ExecutorService,编写并发异步任务的代码就像写顺序程序一样,不用关心线程的创建和协调,只需要提交任务、处理结果就可以了,大大简化了开发工作

6. 怎样理解 Future?

答:

  • Future 接口定义:

    public interface Future<V> {
        boolean cancel(boolean mayInterruptIfRunning);
        boolean isCancelled();
        boolean isDone();
        V get() throws InterruptedException, ExecutionException;
        V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
    }
    
  • get() 方法用于返回异步任务最终的结果,如果任务还未执行完成,会阻塞等待;带参数的 get() 方法可以限定阻塞等待的时间,如果超时任务还未结束,会抛出 TimeoutException 异常。
  • cancel() 用于取消异步任务,如果任务已完成、或已经取消、或由于某种原因不能取消,cancel() 返回 false,否则返回 true。如果任务还未开始,则不再运行。但如果任务已经在运行,则不一定能取消,参数 mayInterruptIfRunning 表示,如果任务正在执行,是否调用 interrupt() 方法中断线程,如果为 false,就不会,如果为 true,就会尝试中断线程,虽然中断不一定能取消线程
  • isDone()isCancelled() 用于查询任务状态。isCancelled() 表示任务是否被取消,只要 cancel() 方法返回了 true,随后的 isCancelled() 方法都会返回 true,即使执行任务的线程还未真正结束。isDone() 表示任务是否结束,不管什么原因都算,可能是任务正常结束,可能是任务抛出了异常,也可能是任务被取消。
  • 对于 get() 方法,如果调用 get() 方法的线程被中断了,get() 方法会抛出 InterruptedException 异常,任务最终大概有三种结果
    • 正常完成get() 方法会返回其执行结果,如果任务是 Runnable 且没有提供结果,返回 null
    • 任务执行抛出了异常get() 方法会将异常包装为 ExecutionException 重新抛出,通过异常的 getCause() 方法可以获取原异常。
    • 任务被取消了get() 方法会抛出异常 CancellationException
  • Future 是一个重要的概念,是实现“任务的提交”与“任务的执行”相分离的关键,是其中的“纽带”,任务提交者和任务执行服务通过它隔离各自的关注点,同时进行协作

7. 【笔试题】手写一个任务执行服务 Demo?

答:

public class BasicDemo {
    static class Task implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            int sleepSeconds = new Random().nextInt(1000);
            Thread.sleep(sleepSeconds);
            return sleepSeconds;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor(); // 使用工厂类 Executors 创建了一个任务执行服务,表示使用一个线程执行所有服务
        Future<Integer> future = executor.submit(new Task());
        // 模拟执行其他任务
        Thread.sleep(100);
        try {
            System.out.println(future.get());
        } catch(ExecutionException e) {
            e.printStackTrace();
        }
        executor.shutdown(); // 关闭任务执行服务
    }
}

8. ExecutorService 的基本实现原理?

答:

  • ExecutorService 的主要实现类是 ThreadPoolExecutor,它是基于线程池实现的
  • ExecutorService 还有一个抽象实现类 AbstractExecutorService
  • AbstractExecutorService 提供了 submit()invokeAll()invokeAny() 的默认实现,子类需要实现其他方法。除了 execute(),其他方法都与执行服务的生命周期管理有关。submit()invokeAll()invokeAny() 最终都会调用 execute()execute() 决定了到底如何执行任务

9. Future 的基本实现原理?

答:

  • Future 的主要实现类是 FutureTask
  • FutureTask 实现了 RunnableFuture 接口
  • RunnableFuture 接口既扩展了 Runnable,又扩展了 Future,没有定义新方法。作为 Runnable,它表示要执行的任务,传递给 execute() 方法进行执行;作为 Future,它又表示任务执行的异步结果

10. 【笔试题】手写一个简单的 ExecutorService 实现类?

答:

public class SimpleExecutorService extends AbstractExecutorService {
    @Override
    public void shutdown() {
    }
    @Override
    public List<Runnable> shutdownNow() {
        return null;
    }
    @Override
    public boolean isShutdown() {
        return false;
    }
    @Override
    public boolean isTerminated() {
        return false;
    }
    @Override
    public boolean awaitTermination(long itmeout, TimeUnit unit) throws InterruptedException {
        return false;
    }
    @Override
    public void execute(Runnable command) {
        new Thread(command).start();
    }
}

原文:大专栏  Java 异步任务执行服务(一):基本概念和原理

原文地址:https://www.cnblogs.com/dajunjun/p/11640356.html

时间: 2024-11-05 23:20:39

Java 异步任务执行服务(一):基本概念和原理的相关文章

Java异步非阻塞IO NIO使用与代码分析

[TOC] Java异步非阻塞IO NIO使用与代码分析 TimeServer程序的NIO实现完整代码 TimeServer程序来自书本<Netty权威指南>,nio的代码确实有些难懂(这也是后面需要使用Netty的原因之一),不过我对代码加了注释,这样一来对nio的概念及基本的使用都会有一个非常清晰的认识: 服务端程序 TimeServer.java: package cn.xpleaf.nio; public class TimeServer { public static void ma

oracle实例名,数据库名,服务名等概念差别与联系

数据库名.实例名.数据库域名.全局数据库名.服务名 这是几个令非常多刚開始学习的人easy混淆的概念.相信非常多刚開始学习的人都与我一样被标题上这些个概念搞得一头雾水.我们如今就来把它们弄个明确. 一.数据库名 什么是数据库名?数据库名就是一个数据库的标识,就像人的身份证号一样.他用參数DB_NAME表示,如果一台机器上装了多全数据库,那么每个数据库都有一个数据库名.在数据库安装或创建完毕之后,參数DB_NAME被写入參数文件之中.格式例如以下:DB_NAME=myorcl...在 创建数据库时

Java异步编程——深入源码分析FutureTask

Java的异步编程是一项非常常用的多线程技术. 之前通过源码详细分析了ThreadPoolExecutor<你真的懂ThreadPoolExecutor线程池技术吗?看了源码你会有全新的认识>.通过创建一个ThreadPoolExecutor,往里面丢任务就可以实现多线程异步执行了. 但之前的任务主要倾向于线程池,并没有讲到异步编程方面的内容.本文将通过介绍Executor+Future框架(FutureTask是实现的核心),来深入了解下Java的异步编程. 万事从示例开始,我们先通过示例D

Java中的泛型 (上) - 基本概念和原理

本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以深刻理解容器类.那,泛型到底是什么呢? 什么是泛型? 一个简单泛型类 我们通过一个简单的例子来说明泛型类的基本概念.实现原理和好处. 基本概念 我们直接来看代码: public class Pair<T> { T first; T second; public Pair(T first, T se

如何注册java程序为windows服务

如何注册java 程序为windows 服务 最近想找个软件来控制电脑的关机时间,在网上找了几个,都是可视化界面的可以设置具体的关机时间的软件.由于我想编写的关机程序是运行在别人机器上,只能让该机器在晚上17 点到23 点25 分才上网,到了23 点25 分就可以自动关机.为了让别人感觉不到这个软件的“存在”(免得使用者自己关闭定时关机软件),所以我想把关机软件注册为服务的方式,运行在后台.这里介绍下如何利用javaService 软件把java 程序注册为windows 服务. 一.  利用j

捕获Java线程池执行任务抛出的异常

Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常, public interface Runnable { public abstract void run();} 那么如果 run() 方法中抛出了RuntimeException,将会怎么处理了? 通常java.lang.Thread对象运行设置一个默认的异常处理方法: java.lang.Thread.setDefaultUncaughtExceptionHandler(UncaughtExce

Java新手入门的30个基本概念

Java新手入门的30个基本概念 在我们学习Java的过程中,掌握其中的基本概念对我们的学习无论是J2SE,J2EE,J2ME都是很重要的,J2SE是Java的基础,所以有必要对其中的基本概念做以归纳,以便大家在以后的学习过程中更好的理解java的精髓,在此我总结了30条基本的概念. Java概述: 目前Java主要应用于中间件的开发(middleware)---处理客户机于服务器之间的通信技术,早期的实践证明,Java不适合pc应用程序的开发,其发展逐渐变成在开发手持设备,互联网信息站,及车载

WPF异步调用WCF服务

wpf调用wcf时,第一次访问总耗时到达几秒,影响界面的用户体验,因此在wpf加载界面和加载数据时采用异步加载,即异步访问wcf服务, 由于是否采用异步加载和服务端无关,仅仅由客户端自己根据需要来选择,则我们只需要在客户端(WPF)程序中采用异步的方法.如下: //1.创建一个异步对象,访问wcfFunc<string, string, List<NodeItem>> GetDataFromWCF = new Func<string, string, List<Node

Java应用Tomcat执行过程之性能调优

Java应用Tomcat执行过程之性能调优(整理两天时间.转载请注出处) 1.简介 Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台.安全域管理和Tomcat阀等. Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并