并发编程之同步/异步/回调/任务 工作流程分析图解

在现代软件开发中,多线程和异步编程已成为提升应用性能和响应速度的关键技术。Java提供了强大的并发工具,如ThreadRunnableCallableFuture,这些工具使开发者能够有效地管理线程和任务。ThreadRunnable允许我们创建和执行线程,而CallableFuture则提供了异步计算结果的机制。这些工具和概念不仅帮助我们解决了多线程环境下的复杂问题,还提供了处理暂时性故障和优化资源访问的策略。对于任何希望深入理解并发编程的Java开发者来说,掌握这些基础概念和工具是必不可少的。

1、同步与异步

1.1 同步与异步设计图

  1. 同步处理:指向同步处理的节点,包括阻塞当前线程、顺序执行和等待结果。
  2. 异步处理:指向异步处理的节点,包括不阻塞当前线程、并行执行和回调结果。
  • 同步处理

    • 阻塞当前线程:在等待操作完成时,当前线程不能执行其他任务。
    • 顺序执行:任务按照顺序一个接一个地执行。
    • 等待结果:线程等待操作完成并获取结果。
  • 异步处理

    • 不阻塞当前线程:在等待操作完成时,当前线程可以继续执行其他任务。
    • 并行执行:多个任务可以同时执行,提高效率。
    • 回调结果:操作完成后,通过回调函数或其他机制返回结果。

1.2 同步处理时序图

  1. 客户端请求数据:客户端发起一个请求,要求同步API提供数据。
  2. 同步API查询数据库:同步API将请求转发到数据库。
  3. 数据库返回结果:数据库处理请求并将结果返回给同步API。
  4. 同步API返回结果:同步API将数据库的结果返回给客户端。

1.3 异步处理时序图

  1. 客户端发起异步请求:客户端向异步API发起一个请求,要求查询数据,但不会等待响应。
  2. 异步API查询数据库:异步API将查询任务发送到数据库,并立即返回,不会阻塞。
  3. 数据库处理完毕:数据库在后台处理查询任务。
  4. 调用回调函数:一旦数据库处理完毕,异步API调用预先定义的回调函数。
  5. 返回结果给客户端:回调函数将结果返回给客户端。

1.3 回调时序图

  1. 客户端注册回调并发起异步请求:客户端向异步API发起请求,并提供一个回调函数,用于在异步操作完成后接收结果。
  2. 异步API立即返回:异步API接收请求后立即返回,不等待异步操作完成。
  3. 客户端继续执行:客户端可以继续执行其他任务,而不必等待异步操作的结果。
  4. 异步API执行异步操作:异步API在后台执行异步操作。
  5. 异步操作完成:一旦异步操作完成,异步API调用之前注册的回调函数。
  6. 回调执行:回调函数被执行,处理异步操作的结果。
  7. 返回结果给客户端:回调函数将异步操作的结果返回给客户端。

2、任务执行单元

2.1 Thread 工作模式

  1. 创建 Thread 对象 :通过 new Thread() 或其子类构造函数创建一个新的线程对象。
  2. 设置 Runnable 任务 :为线程对象设置一个实现了 Runnable 接口的任务。
  3. 启动线程 :调用线程对象的 start() 方法来启动线程。
  4. 线程状态 :线程可以处于以下几种状态之一:
    • 运行中 :线程正在执行其 run() 方法。
    • 阻塞:线程等待监视器锁。
    • 等待:线程等待某个条件或超时。
    • 终止:线程执行完毕或被中断。
  5. 执行 run 方法 :线程开始执行其 run() 方法。
  6. 调用 Runnable.runThread 类的 run() 方法内部调用 Runnable 任务的 run() 方法。
  7. 执行任务 :实际的 Runnable 任务开始执行。
  8. 任务执行完毕Runnable 任务执行完毕。
  9. 线程结束:任务执行完毕后,线程结束其生命周期。
  10. 等待解锁:如果线程需要访问同步代码块或方法,它可能会因为等待锁而被阻塞。
  11. 等待条件 :线程可能在 wait()join() 或其他等待条件下等待。

3、任务单元

3.1 Runnable 无返回值

Runnable 接口设计

Runnable 接口是 Java 中的一个功能性接口,用于那些可以被线程执行的任务。它只包含一个方法 run(),该方法不接受参数,也不返回任何值(即返回类型为 void)。

接口定义
java 复制代码
@FunctionalInterface
public interface Runnable {
    void run();
}
使用 Runnable 的步骤
  1. 实现 Runnable 接口 : 创建一个类实现 Runnable 接口,并覆盖 run() 方法来定义任务的执行逻辑。
java 复制代码
public class MyRunnableTask implements Runnable {
    @Override
    public void run() {
        // 任务执行的代码
        System.out.println("任务正在执行");
    }
}
  1. 创建 Thread 对象 : 创建 Thread 对象时,将实现了 Runnable 接口的类的实例作为参数传递给 Thread 构造函数。
java 复制代码
public class Main {
    public static void main(String[] args) {
        MyRunnableTask task = new MyRunnableTask();
        Thread thread = new Thread(task);
        thread.start(); // 启动线程,执行任务
    }
}
  1. 启动线程 : 调用 Thread 对象的 start() 方法来启动线程。这将导致在新线程中异步执行 run() 方法。

3.2 Callable 有返回值

Callable 接口设计

Callable接口是Java并发编程中的一部分,它允许任务返回结果和抛出异常。以下是Callable接口的基本设计和用法的说明:

接口定义
java 复制代码
@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}
  • Callable<V>Callable是一个泛型接口,V代表返回值的类型。
  • call():这是一个方法,它不接受任何参数,可以返回任何类型的值(V),并且可以抛出任何类型的异常。
使用 Callable 的步骤
  1. 实现 Callable 接口 : 创建一个类实现 Callable 接口,并覆盖 call() 方法来定义任务的执行逻辑和返回结果。
java 复制代码
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        // 任务执行的代码
        return "任务结果";
    }
}
  1. 创建 FutureTask 对象 : 将实现了 Callable 接口的类的实例传递给 FutureTask 构造函数。
java 复制代码
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable task = new MyCallable();
        FutureTask<String> futureTask = new FutureTask<>(task);
        Thread thread = new Thread(futureTask);
        thread.start(); // 启动线程,执行任务

        // 获取任务结果
        String result = futureTask.get();
        System.out.println("任务结果: " + result);
    }
}
  1. 启动线程 : 调用 Thread 对象的 start() 方法来启动线程。这将导致在新线程中异步执行 FutureTaskrun() 方法,该方法内部会调用 Callablecall() 方法。

4、异步结果

4.1 Future

  1. 提交异步任务 :通过 ExecutorService 提交一个异步任务。
  2. ExecutorService:执行异步任务的服务。
  3. Future对象ExecutorService 提交任务后返回一个 Future 对象,该对象可以用来检查计算是否完成、等待计算完成、取消任务和获取计算结果。
  4. 检查完成 :通过 Future 对象的 isDone() 方法检查异步任务是否已完成。
  5. 已完成 :如果任务已完成,通过 Future 对象的 get() 方法获取结果。
  6. 获取结果:处理异步任务的结果。
  7. 未完成:如果任务未完成,可以选择等待或取消任务。
  8. 等待或取消:等待任务完成或取消任务。
  9. 等待超时:设置超时时间等待任务完成。
  10. 取消任务:尝试取消任务。
  11. 处理结果:处理异步任务的结果。
  12. 处理超时:处理等待超时的情况。
  13. 处理取消 :处理任务取消的情况
  14. 客户端提交任务 :客户端向执行器服务提交一个实现了 Callable 接口的异步任务。
  15. 执行器服务执行任务:执行器服务接收到任务后,开始执行异步任务。
  16. 异步任务设置结果 :异步任务执行完毕后,将结果设置到与 Future 对象关联的内部存储中。
  17. 客户端获取结果 :客户端调用 Future 对象的 get() 方法来获取异步任务的结果。
  18. 任务已完成 :如果异步任务已经完成,Future 对象将返回结果给客户端。
  19. 任务未完成 :如果异步任务还未完成,Future 对象将导致客户端阻塞等待,直到任务完成并返回结果。
  • Future :这是一个接口,定义了以下方法:
    • cancel(boolean mayInterruptIfRunning):尝试取消执行任务。
    • isCancelled():检查任务是否已被取消。
    • isDone():检查任务是否已完成。
    • get():获取任务的结果,如果任务尚未完成,则阻塞等待。
    • get(long timeout, TimeUnit unit):在指定的超时时间内获取任务的结果。

4.2 FutureTask

  1. 创建 FutureTask 对象 :创建一个 FutureTask 对象,它封装了一个 Callable 对象(如果任务有返回值)或 Runnable 对象(如果任务没有返回值)。
  2. 提交任务 :决定是通过 ExecutorService 提交任务还是直接在当前线程执行。
  3. 执行任务 :如果通过 ExecutorService 提交,任务将被安排在线程池中的某个线程执行。如果是直接执行,则调用 FutureTaskrun 方法。
  4. 任务状态:检查任务的执行状态。
  5. 完成:如果任务正常完成,则设置任务的结果。
  6. 被取消:如果任务在执行前被取消,则标记任务为取消状态。
  7. 异常:如果任务执行过程中抛出异常,则设置异常信息。
  8. 提供结果给调用者 :一旦任务完成(无论是正常完成、被取消还是抛出异常),FutureTask 将能够提供结果给调用 get 方法的线程。
  9. 客户端提交任务 :客户端向执行器服务提交一个实现了 Callable 接口的任务。
  10. 执行器服务创建 FutureTask :执行器服务接收到任务后,创建一个 FutureTask 对象来封装这个任务。
  11. 执行任务 :执行器服务执行 FutureTaskrun() 方法,这将导致在新线程中异步执行 Callable 任务的 call() 方法。
  12. 执行任务逻辑Callable 任务执行其逻辑,并可能设置结果或异常。
  13. 通知完成 :如果客户端已经调用了 FutureTaskget() 方法并正在等待,FutureTask 将通知客户端任务已完成。
  14. 客户端获取结果 :客户端调用 FutureTaskget() 方法来获取异步任务的结果。
  15. 任务已完成 :如果任务已完成,FutureTask 返回结果给客户端。
  16. 任务未完成 :如果任务未完成,FutureTask 将导致客户端阻塞等待。
  • FutureTask :这是一个类,它实现了 RunnableFuture 接口。它包含任务的执行结果(result)、任务完成状态(done)和取消状态(cancelled)。
  • Callable:这是一个接口,它允许任务返回结果和抛出异常。
  • Runnable:这是一个接口,它允许任务被线程执行,但不返回结果和异常。
  • TimeUnit :这是一个枚举,它定义了时间单位,用于 get 方法的超时参数。
相关推荐
除了代码啥也不会14 分钟前
springboot 整合 rabbitMQ (延迟队列)
java·分布式·rabbitmq
xq51486316 分钟前
内存分配与回收策略
java·开发语言·jvm
cuisidong199732 分钟前
springmvc 用了 @RequestMapping 是不是可以不用
java·开发语言
《源码好优多》33 分钟前
基于Java Springboot公园管理系统
java·开发语言·spring boot
我救我自己33 分钟前
UE5 slate BlankProgram独立程序系列
java·开发语言·ue5
fa_lsyk35 分钟前
Spring:AOP面向切面编程入门案例
java·后端·spring
泰山小张只吃荷园1 小时前
SCAU软件体系结构实验四 组合模式
java·开发语言·组合模式
杨半仙儿还未成仙儿1 小时前
java中链表的数据结构的理解
java·数据结构·链表
bin91531 小时前
【热门主题】000062 云原生后端:开启高效开发新时代
后端
多来米19962 小时前
小白学多线程(持续更新中)
java·开发语言