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

news2024/10/7 18:32:32

文章目录

    • 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对象,需要自己处理任务的返回值和异常。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

concurrency 并行编程

Goroutine go语言的魅力所在,高并发。 线程是操作系统调度的一种执行路径,用于在处理器执行我们在函数中编写的代码。一个进程从一个线程开始,即主线程,当该线程终止时,进程终止。这是因为主线程是应用程序的原点。然后…

LeetCode题练习与总结:二叉树的层序遍历Ⅱ--107

一、题目描述 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:[…

springboot3微服务下结合springsecurity的认证授权实现

1. 简介 在微服务架构中,系统被拆分成许多小型、独立的服务,每个服务负责一个功能模块。这种架构风格带来了一系列的优势,如服务的独立性、弹性、可伸缩性等。然而,它也带来了一些挑战,特别是在安全性方面。这时候就体…

YOLOv5改进策略:Focaler-IoU损失函数改进

文章目录 1、前言2、摘要3、Focaler-IoU:4、代码实现5、目标检测系列文章 1、前言 ​ 目标检测是计算机视觉的基本任务之一,旨在识别图像中的目标并定位其位置。目标检测算法可分为基于锚点和无锚点的方法。基于锚点的方法包括Faster R-CNN、YOLO系列、…

数据结构 —— 栈 与 队列

1.栈 1.1栈的结构和概念 栈(Stack)是一种特殊的线性数据结构,它遵循后进先出(LIFO,Last In First Out)的原则。栈只允许在一端插入和删除数据,这一端被称为栈顶(top)&a…

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

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

基于SpringBoot和Mybatis实现的留言板案例

目录 一、需求及界面展示 二、准备工作 引入依赖 .yml文件相关配置 数据库数据准备 三、编写后端代码 需求分析 代码结构 Model Mapper Service Controller 前端代码 四、测试 一、需求及界面展示 需求: 1. 输入留言信息,点击提交&…

2024-6-遥远的救世主

2024-6-遥远的救世主 2024-4-18 豆豆 fatux: 2021.5.26 看完电视剧《天道》之后购买本书,断断续续一直没有读完。 非常好奇,一个什么样的作者能写出如此奇书。老丁,一个智者,智者是多么孤独,因为找不到同…

AtCoder Regular Contest 178 A~D

A.Good Permutation 2(贪心) 题意: 给你一个正整数 N N N和一个由 M M M个正整数 A ( A 1 , A 2 , … , A M ) A(A_{1},A_{2}, \dots,A_{M}) A(A1​,A2​,…,AM​)组成的序列。 在这里, A A A的所有元素都是介于 1 1 1和 N N …

nss做题

[NCTF 2018]签到题 1.f12在index.php中找到flag [NSSCTF 2022 Spring Recruit]ezgame 1.在js源码中就有flag [UUCTF 2022 新生赛]websign 1.打开环境后发现ctrlu和右键,f12都被禁用了。两种方法,第一种:禁用js;第二中提前打开…

数据结构(五)树与二叉树

2024年5月26日一稿(王道P142) 基本概念 术语 性质 二叉树 5.2.2 二叉树存储结构

vue3中基于element-plus封装一个表格弹框组件,要求可以单选和多选table数据

单选&#xff1a; <template><SelectMaterialref"selectMaterialRef"check"checkbox"select"selectMaterial"></SelectMaterial><el-button type"primary" size"small" icon"el-icon-plus"…

【STM32】新建工程(江科大)

文章目录 STM32的开发方式库函数文件夹一、新建一个基于标准库的工程1.建立一个存放工程的文件夹2.打开Keil5 二、通过配置寄存器来完成点灯1.配置RCC寄存器2.配置PC13口&#xff08;1&#xff09;配置PC13口的模式&#xff08;2&#xff09;给PC13口输出数据 三、为寄存器添加…

与MySQL的初相遇

&#x1f30e;初识MySQL 注&#xff1a;本文SQL语句只为了验证猜想&#xff0c;不会也不要紧。 文章目录&#xff1a; MySql开端 认识数据库       什么是数据库       主流数据库       MySQL的本质 MySQL基础使用       连接mysql服务器     …

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

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

图片AI高效生成惊艳之作,一键解锁无限创意,轻松打造概念艺术新纪元!

在数字化时代&#xff0c;图片已经成为我们表达创意、传递信息的重要载体。然而&#xff0c;传统的图片生成方式往往耗时耗力&#xff0c;无法满足我们对于高效、创意的需求。幸运的是&#xff0c;现在有了图片AI&#xff0c;它以其高效、智能的特点&#xff0c;为我们带来了全…

数组-最接近给出数字的三数之和

题目描述 解题思路 这里使用三层for循环&#xff0c;暴力解法穷举所有三个数和的可能性&#xff0c;注意三层循环里的索引不要重复。 代码实现 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返…

C语言——小知识和小细节19

一、奇数位与偶数位互换 1、题目介绍 实现一个宏&#xff0c;将一个整数的二进制补码的奇数位与偶数位互换。输出格式依旧是十进制整数。示例&#xff1a; 2、分析 既然想要交换奇数位和偶数位上的数字&#xff0c;那么我们就要先得到奇数位和偶数位上的数字&#xff0c;那么…

THREE.JS中的向量点乘,以及他的几何意义。

1. THREE.JS中的向量点乘&#xff0c;以及他的几何意义 向量点乘的公式 : 2. 在three.js 中计算向量点乘 const a new THREE.Vector3(10, 10, 0); const b new THREE.Vector3(20, 0, 0); const dot a.dot(b);从这里可以看出&#xff0c;向量的点乘的结果是一个数字(标量…

嵌入式进阶——LED呼吸灯(PWM)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 PWM基础概念STC8H芯片PWMA应用PWM配置详解占空比 PWM基础概念 PWM全称是脉宽调制&#xff08;Pulse Width Modulation&#xff09…