Java 异步编程——Java内置线程调度器(Executor 框架)

文章目录

    • Java多线程的两级调度模型
    • Executor 框架
      • Executor 框架的组成概念
      • Executor 框架中任务执行的两个阶段:任务提交和任务执行

在 Java1.5 以前,开发者必须手动实现自己的线程池;从 Java1.5 开始,Java 内部提供了线程池。

在Java 异步编程——既然可以手动创建线程,为什么还要使用线程池这篇文章提到过Java线程会映射到操作系统本地线程上,使得 Java 线程能够在操作系统层面上得到执行,在大多数情况下,每个 Java 线程都会对应一个本地操作系统线程,但具体的映射方式和数量由 JVM 和操作系统的实现决定。这里Java线程与操作系统本地线程两个层次的线程模型,存在两个层次的调度机制。所以在介绍Java内置线程池之前,先一起了解Java多线程的两级调度模型。

Java多线程的两级调度模型

Java 多线程的两级调度模型是指在 Java 多线程程序中,存在两个层次的调度机制:用户级调度和操作系统级调度。

用户级调度:(用户级线程 ULT)

  • 用户级线程由 Java 虚拟机(JVM)自身管理,不需要操作系统内核的介入。
  • 用户级调度是指由应用程序自身实现的线程调度机制。在这一级别上,应用程序可以使用 Java 提供的并发编程工具(例如 Executor 框架、线程池等用户级的调度器)来管理和调度线程。应用程序根据自身的需求,将任务分配给可用的Java线程,决定线程的执行顺序和优先级等。Java 线程是由 JVM 提供的线程管理机制来调度执行的,所以用户级调度是在 Java 层面上进行的,不涉及操作系统的线程调度。

操作系统级调度:(内核级线程 KLT)

  • 内核级线程是由操作系统内核管理的真正的系统级线程。
  • 操作系统级调度是指操作系统内核对线程进行的调度和执行。在这一级别上,操作系统负责将Java线程映射到底层的操作系统线程(本地操作系统线程),并分配 CPU 进行实际的计算。操作系统线程模型可以利用操作系统提供的并发机制和资源管理功能,如线程调度器、线程优先级、时间片轮转等,以确保公平性和资源利用的最大化。

两级调度模型的优势:

Java 多线程的两级调度模型的优势在于结合了用户级调度和操作系统级调度的特点:

  • 用户级调度使应用程序具有灵活性和可控性,可以根据具体需求自主管理和调度线程。Java 线程模型提供了高级的并发编程抽象,使得开发者可以更方便地编写并发程序,从而可以根据任务的特点和优先级,自主决定线程的创建、启动、休眠、唤醒等操作,实现更细粒度的线程调度。
  • 操作系统级调度利用了底层操作系统的调度机制和资源管理功能,确保线程的公平性和高效利用。操作系统级调度可以根据底层硬件的特点和系统负载情况,智能地分配线程执行的资源,提高性能和资源利用率。
  • 用户级线程的创建、切换和调度都发生在 JVM 内部,效率较高;内核级线程的创建、切换和调度需要操作系统内核的参与,开销相对较大。
  • 当一个用户级线程阻塞(如进行 I/O 操作)时,如果是单线程,整个进程也会被阻塞,无法利用其他可用的 CPU 资源;在多线程情况下,JVM 会将其挂起,并将另一个可运行的用户级线程映射到内核级线程上继续执行,避免了进程级的阻塞,提高整体并发性能。
    在这里插入图片描述

Executor 框架

上面讲述了 Java 多线程的两级调度模型,对于Java编程,我们只需关注用户级调度(Java线程)。Java 多线程管理是由在 Java 内置的 Executor 框架下完成的。Executor 框架是 Java 5 引入的一套用于异步任务执行的API,提供了一种简化线程管理和任务执行的方式,将任务的提交和执行分离开来。

Executor 框架的组成概念

首先简单介绍一下 Executor 框架的组成概念。

  1. 任务:任务指的是被异步执行的工作单元(工作代码),任务需要实现接口:Runable 接口 or Callable 接口;
    • Runable 接口:只定义了一个没有返回值的 run() 方法,用于封装需要执行的任务代码
    • Callable 接口:只定义了一个带返回值的 call() 方法,用于封装需要执行的任务代码并返回结果。
  2. 任务执行器:负责实际执行任务的组件,包括任务执行机制的核心接口 Executor,以及继承自 Executor 的 ExecutorService 接口。Executor 框架有几个关键类实现了 ExecutorService 接口:ThreadPoolExecutor 和 ScheduledThreadPoolExecutor、ForkJoinPool;
    • Executor 接口:任务执行器的核心接口,定义了一个简单的 execute(Runnable command) 方法用于异步执行任务。
    • ExecutorService 接口:继承自 Executor 接口,添加了更丰富的任务提交和生命周期管理方法,如 submit(Callable task)、submit(Runnable task) 、shutdown() 等。
      • submit(Callable task)方法返回一个Future对象,可以通过Future对象的get()方法获取任务的返回值。
      • submit(Runnable task)方法返回一个Future对象,但该Future对象的get()方法返回null。
    • ThreadPoolExecutor 类:是 Executor 框架中最重要的任务执行器实现,实现了 ExecutorService 接口。提供了一个可配置的线程池,用于执行异步任务。
    • ScheduledThreadPoolExecutor 类:继承自 ThreadPoolExecutor,额外提供了定时和周期性任务执行的功能。
    • ForkJoinPool 类:提供了一个支持工作窃取算法的线程池实现,适用于分治类型的并行计算。
  3. 获取任务执行结果:包括 Future 接口和实现 Future 接口的 FutureTask 类、ForkJoinTask 类。
    • Future 接口:获取任务执行结果核心接口,定义获取异步任务执行结果的相关方法。当提交 Callable 任务时,会返回一个 Future 对象。通过这个 Future 对象对应方法可以查询任务的执行状态、获取执行结果、取消任务等。还提供了丰富的 API,如 get()、isDone()、cancel() 等,用于管理异步任务的生命周期。
    • FutureTask 类:Future 接口的一个具体实现类。
    • ForkJoinTask 抽象类:继承自 Future 接口,用于支持 ForkJoinPool 中任务的异步计算。ForkJoinTask 提供了 fork() 和 join() 方法,用于将任务拆分并行执行,然后合并结果。

Executor框架的使用示意图:
在这里插入图片描述

Executor 框架中任务执行的两个阶段:任务提交和任务执行

前面分析 Executor 框架时,Executor 接口只有一个执行任务的方法 execute(),ExecutorService 接口增加了一个提交任务的方法 submit()。从系统层面来讲,这两个方法都是任务提交方法,如果任务只是简单的异步执行,不需要返回值或处理异常,可以直接使用 execute() 进行任务提交;如果任务需要返回值或处理异常,则使用 submit() 方法进行提交。再深入代码研究,submit() 方法最终还是会调到 execute() 实现最终的任务提交,可以理解 submit() 在任务提交前进行了一系列处理,使其能够在任务执行完后获得返回值或处理异常。submit() 方法在 AbstractExecutorService 抽象类中由默认实现,execute() 在 ThreadPoolExecutor 类中实现。最后,Executor 根据线程池的配置和调度策略分配线程执行任务。

ThreadPoolExecutor 继承 AbstractExecutorService 实现 ExecutorService。

两个阶段:

  • 任务提交阶段:在任务提交阶段,应用程序通过调用 Executor 类的 execute(Runnable command) 或 ExecutorService 的 submit(Callable task) 方法将任务提交给 Executor。在这个阶段,任务被封装成一个任务对象,可以是 Runnable 对象或 Callable 对象,并被添加到任务队列中等待执行。当任务被提交后,Executor 实现类会对任务进行排队和调度。

  • 任务执行阶段:在任务执行阶段,Executor 根据线程池的配置和调度策略,从它管理的线程池中分配一个空闲线程来执行任务。线程从任务队列中取出任务,并调用任务的 run() 或 call() 方法来执行任务。任务执行完成后,线程会被返回到线程池中,等待被再次分配执行新的任务。

任务提交阶段可以根据应用程序的需要灵活地控制任务的产生和提交,任务执行阶段则由 Executor 框架负责管理和调度线程的执行,从而实现更高的并发性能和更好地利用系统资源。这种将任务的提交和执行解耦,开发者只需关注任务的定义和提交,而无需过多地关注任务的执行细节。可以根据实际需求来调整任务队列的容量、任务队列的类型、拒绝策略以及线程池的配置(线程池的大小)等参数。

new Thread 创建线程与任务执行:

在学习 Java 线程时,都曾看到过Java创建多线程的三种方式:继承Thread类、实现Runnable接口以及实现Callable接口。经过前面的分析,Runnable接口和Callable接口都是代表任务接口,封装要执行的任务代码。实现Runnable接口以及实现Callable接口两种方式严格来说不是创建线程,而真正创建多线程的方式只有一种:继承Thread类,只有通过 new Thread().start() 这种方式才能真正的创建Java线程并映射到操作系统的内核线程上。

其实上述三种方式更好的理解是创建并提交任务的三种方式,相比之下:

  1. 解耦任务逻辑:直接创建 Thread 对象会将任务逻辑和线程管理耦合在一起,不利于代码的维护和扩展;而使用 Runnable 或 Callable 接口可以将任务的逻辑与线程的管理分离开来,使得代码更加模块化和可复用。
  2. 线程池管理:经过前面的分析,使用 Runnable 或 Callable 接口可以将任务提交给线程池(ExecutorService)进行管理和执行,多个任务可以方便复用多个线程执行处理,从而避免频繁创建和销毁线程的开销;而直接创建 Thread 对象,需要自己管理线程的生命周期,比较麻烦。
  3. 任务结果和异常处理:Callable接口可以返回任务的执行结果和异常处理,Runnable接口虽然不能返回结果,但也可以通过Future对象获取任务的执行状态和异常信息,而直接创建Thread对象,需要自己处理任务的返回值和异常。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/645858.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VMware虚拟机如何与主机共享文件夹

本机:WIN10 VMware虚拟机:WIN7 因为每次配置都爱忘记操作,目标是为了在WIN7虚拟机中可以访问本机文件 首先本机操作 新建一个共享文件夹,不带中文目录(最好不要) 点击共享 选择everyone,记得权限"读取和写入" 然后到虚拟机里面 添加一个网络位置 点击浏览,选择网…

C++面向对象程序设计-北京大学-郭炜【课程笔记(十一)】

C面向对象程序设计-北京大学-郭炜【课程笔记(十一)】 1、string(重要知识点)1.2、string的赋值和链接1.3、比较string1.4、子串1.5、交换string1.6、寻找string中的字符1.7、删除string中的字符1.8、替换string中的字符1.9、在str…

【C++】---多态

【C】---多态 一、多态的概念二、多态的定义及实现1、构成多态的2个必要条件2、什么叫做虚函数的重写?3、虚函数重写的3个例外4、建议把 析构函数 都定义为:虚函数 三、C11的两个关键字:final override1、final:修饰虚函数&#x…

k8s集群中pod的容器资源限制和三种探针

一、资源限制 总结: requests表示创建pod时预留的资源,limits表示pod能够使用资源的最大值。requests值可以被超,limits值不能超过,如果是内存使用超过limits会触发oom然后杀掉进程,如果是cpu超过limits会压缩cpu的使用…

Hudi 多表摄取工具 HoodieMultiTableStreamer 配置方法与示例

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

【Linux初探】:解锁开源世界的神秘钥匙

文章目录 🚀一、了解Linux🔥二、Linux 的发行版❤️三、Linux应用领域💥四、Linux vs Windows & mac 🚀一、了解Linux Linux是一种自由、开放源代码的操作系统,它的内核由芬兰计算机科学家Linus Torvalds在1991年创…

【九十四】【算法分析与设计】练习四蛮力法练习,排列问题和组合问题,求解最大连续子序列和问题,求解幂集问题,求解0/1背包问题,求解任务分配问题

求解最大连续子序列和问题 给定一个有n(n≥1)个整数的序列,要求求出其中最大连续子序列的和。 例如: 序列(-2,11,-4,13,-5,-2)的最大子序列和为20…

机器人支持回调接口配置(详细教程)

大家伙,我是雄雄,欢迎关注微信公众号:雄雄的小课堂。 一、前言 今天,给大家介绍一下,如何在机器人中配置回调地址和接口编写。很多时候我们可能有这样的场景,收到消息后,想自己处理一下消息的内…

用Python一键生成PNG图片的PowerPoint幻灯片

在当今的商业环境中,PowerPoint演示是展示和传递信息的常用方式。然而,手动将大量图像插入到幻灯片中往往是一项乏味且耗时的工作。但是,通过Python编程,我们可以轻松自动化这个过程,节省时间和精力。 C:\pythoncode\new\folderTOppt.py 在本文中,我将介绍如何使用Python、wx…

Rust开源Web框架Salvo源码编译

1.克隆源码: https://github.com/salvo-rs/salvo.git 2.进入salve目录并运行cargo build编译 编译成功 3.编译生成的库 4.安装salve-cli git clone --recursive https://github.com/salvo-rs/salvo-cli.git 编译salve-cli

人工智能万卡 GPU 集群的硬件和网络架构

万卡 GPU 集群互联:硬件配置和网络设计 一、背景 自从 OpenAI 推出 ChatGPT 以来,LLM 迅速成为焦点关注的对象,并取得快速发展。众多企业纷纷投入 LLM 预训练,希望跟上这一波浪潮。然而,要训练一个 100B 规模的 LLM,通常需要庞大的计算资源,例如拥有万卡 GPU 的集群。以…

Google Play 提示 “您的设备与此版本不兼容“ 解决方案

一、 问题概述Google Play提示“您的设备与此版本不兼容”,无法安装应用。 遇到问题的设备为Xiaomi Mi A3,查了下这台手机的基本信息,Android One系统,版本分为9.0、10.0、11.0。 二、 问题分析Google Play的过滤器 通常有以下5种…

【Nginx <末>】Nginx 基于 IP 地址的访问限制

目录 👋前言 📫一、限制 IP 可以实现哪些功能 👀二、 项目实现 2.1 访问控制实现 2.2 Nginx 配置中指定 IP 地址 💞️三、章末 👋前言 小伙伴们大家好,前面一段时间学习了 Nginx 的相关知识&#xff0c…

RT-DRET在实时目标检测上超越YOLO8

导读 目标检测作为计算机视觉的核心任务之一,其研究已经从基于CNN的架构发展到基于Transformer的架构,如DETR,后者通过简化流程实现端到端检测,消除了手工设计的组件。尽管如此,DETR的高计算成本限制了其在实时目标检测…

React useState基本类型变量的使用

在 React 中,useState 是一个 Hook,用于在函数组件中添加状态,它可以让函数组件拥有状态。基本使用方法如下: // App.jsx import React, { useState } from reactfunction App() {// 使用 useState 创建一个状态变量,初…

如何用Java实现SpringCloud Alibaba Sentinel的熔断功能?

在Java中使用Spring Cloud Alibaba Sentinel实现熔断功能的步骤如下&#xff1a; 添加依赖 在项目的pom.xml文件中添加Spring Cloud Alibaba Sentinel的依赖&#xff1a; <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud…

C语言——malloc和free用法和常见误区

最近写了个关于动态数组的代码&#xff0c;遇到了一个大坑&#xff0c;特此记录 先说结论&#xff1a; 1.利用malloc创建堆空间&#xff0c;大小最好设置大一点&#xff0c;不然后面存进去的值需要的空间过大会导致各种的堆、指针问题 2.只能使用realloc对已经创建的空间进行修…

没有电商经验的人去操作抖音小店,难度大不大?好操作吗?

大家好&#xff0c;我是电商小V 很多新手小伙伴想去操作抖音小店项目&#xff0c;咨询的最多的问题就是我没有电商运营的经验可以去操作吗&#xff1f; 当然是可以操作的&#xff0c;抖音小店项目对于新手来说是一个非常友好的项目&#xff0c;很多小伙伴都是感觉没有电商经验去…

C++——list的实现以及源码

前言&#xff1a; 最近学习了clist的实现&#xff0c;这让我对迭代器的理解又上升了一个新的高度&#xff0c;注意&#xff1a;代码里的list是放在一个叫zgw的命名空间里边&#xff0c;但是在实现list的代码中没有加namespace&#xff0c;这里给个注意&#xff0c;以后复习时能…

整理了10个靠谱且热门的赚钱软件,适合普通人长期做的赚钱副业

作为一名普通的上班族&#xff0c;我们每天都在辛勤工作&#xff0c;但工资的增长速度却如同蜗牛般缓慢。不过&#xff0c;别担心&#xff0c;信息时代总是带给我们无尽的惊喜&#xff01;今天&#xff0c;我将为大家推荐一些赚钱的宝藏软件&#xff0c;让你在闲暇之余轻松实现…