初尝并行编程
进程被分为后台进程和应用进程
大部分后台进程在系统开始运行时被操作系统启动,完成操作系统的基础服务功能。大部分应用进程由用户启动,完成用户所需的具体应用功能
进程由程序段、数据段、进程控制块三部分组成
程序段也被称为是代码段,代码段是进程的操作数据在内存中的位置,包括需要操作的数据集合;程序控制块包含进程的描述信息和控制信息,是进程的存在的唯一标识
程序控制块(Program Control Block,PCB)包含进程的描述信息和控制信息,是进程存在的唯一标 志。
PCB分为四部分
- 进程的描述信息
- 进程ID,进程名称,进程ID是唯一的,进程状态,进程优先级
- 进程的调度信息
- 程序起始地址
- 通信信息
- 进程的资源信息
- 内存信息,内存占用情况和内存管理所用的数据结构
- I/O设备信息
- 文件句柄
- 进程的上下文
- 执行时各种CPU寄存器的值
- 当前线程计数器
- 各种栈值信息
线程由三部分组成
- 线程的描述信息
- 线程ID
- 线程名称
- 线程优先级
- 线程状态
- 其他,例如是否为守护线程
- 程序计数器
- 栈内存
通过实现Runnable接口的方式创建线程目标类
缺点:
- 所创建的类并不是线程类,而是线程的执行目标类
- 如果访问当前线程的属性,不能直接访问Thread的实例方法,必须通过Thread.currentThread()获取当前的线程实例,才能访问和控制当前线程。
优点:
- 避免Java单继承的局限性,如果异步逻辑所在的类已经继承了一个基类,就没办法继承Thread类
- 逻辑和数据更好的分离
继承Thread类实现多线程能更好地做到多个线程并发的完成各自的任务,访问各自的数据
使用Callable和FurtureTask创建线程
RunnableFurture接口
Future接口提供了三大功能:
- 能够取消异步执行的任务
- 判断异步任务是否执行完成
- 获取异步任务完成后的结果
通过线程池创建执行目标提交
private static ExecutorService pool =
Executors.newFixedThreadPool(3);
线程的调度模型
-
分时调度模型
系统平均分配CPU时间片
-
抢占式调度模型
优先级高的优先分配
线程的生命周期
public static enum State {NEW, //新建RUNNABLE, //可执行:包含操作系统的就绪、运
行两种状态BLOCKED, //阻塞WAITING, //等待TIMED_WAITING, //限时等待TERMINATED; //终止}
四种常见状态
-
NEW状态
创建成功但是没有调用start()方 法启动的Thread线程实例都处于NEW状态。
-
RUNNABLE状态
当Java 线程的Thread实例的start()方法被调用后,操作系统中的对应线程进 入的并不是运行状态,而是就绪状态,而Java线程并没有这个就绪状 态。
一旦就绪状态被系统选中,获得CPU时 间片,线程就开始占用CPU,开始执行线程的代码,这时线程的操作系 统状态发生了改变,进入了运行状态。
-
TERMINATED状态
处于RUNNABLE状态的线程在run()方法执行完成之后就变成终止状 态TERMINATED了。
-
TIMED_WAITING状态
线程处于一种特殊的等待状态,准确地说,线程处于限时等待状态。
- Thread.sleep(int n):使得当前线程进入限时等待状态, 等待时间为n毫秒。
- Object.wait():带时限的抢占对象的monitor锁
- Thread.join():带时限的线程合并。
- LockSupport.parkNanos():让线程等待,时间以纳秒为单 位。
- LockSupport.parkUntil():让线程等待,时间可以灵活设置
-
yield仅能使一个线程从运行状态变为就绪状态,而不是阻塞状态
-
yield不能保证使得当前正在运行的线程迅速转换到就绪状 态。
-
即使完成了迅速切换,系统通过线程调度机制从所有就绪线 程中挑选下一个执行线程时,就绪的线程有可能被选中,也有可能不 被选中,其调度的过程受到其他因素(如优先级)的影响
守护线程和用户线程
守护线程在JVM中相当于保姆的角色:只 要JVM实例中尚存在任何一个用户线程没有结束,守护线程就能执行自 己的工作;只有当最后一个用户线程结束,守护线程随着JVM一同结束 工作。
守护线程和用户线程的本质区别是:二者与JVM虚拟机进 程终止的方向不同。用户线程和JVM进程是主动关系,如果用户线程全 部终止,JVM虚拟机进程也随之终止;守护线程和JVM进程是被动关 系,如果JVM进程终止,所有的守护线程也随之终止
使用守护线程需要注意的方面:
- 守护线程必须在启动前将其守护状态设置为true,启动之后 不能再将用户线程设置为守护线程,否则JVM会抛出一个 InterruptedException异常。
- 守护线程存在被JVM强行终止的风险,所以在守护线程中尽 量不去访问系统资源,如文件句柄、数据库连接等。守护线程被强行 终止时,可能会引发系统资源操作不负责任的中断,从而导致资源不 可逆的损坏。
- 守护线程创建的线程也是守护线程。
线程进入就绪状态的条件:
- 调用线程的start()方法,此线程就会进入就绪状态。
- 当前线程的时间片用完
- 线程睡眠(Sleep)操作结束
- 对其他线程合入(Join)操作结束
- 等待用户输入结束
- 线程争抢到对象锁(Object Monitor)
- 当前线程调用了yield()方法让出CPU执行权限
处于阻塞状态的线程不会占用CPU的资源
进入阻塞的情况
- 线程等待获取锁
- IO阻塞
线程的创建
- 必须为线程堆栈分配和初始化大量内存块,其中包含至少 1MB的栈内存
- 需要进行系统调用,以便在OS(操作系统)中创建和注册本 地线程
线程池解决的问题:
- 提升性能:线程池能独立负责线程的创建、维护和分配。在 执行大量异步任务时,可以不需要自己创建线程,而是将任务交给线程池去调度。线程池能尽可能使用空闲的线程去执行异步任务,最大 限度地对已经创建的线程进行复用,使得性能提升明显。
- 线程管理:每个Java线程池会保持一些基本的线程统计信 息,例如完成的任务数量、空闲时间等,以便对线程进行有效管理, 使得能对所接收到的异步任务进行高效调度。
由于创建和销毁线程需要时间以及系统资源开销,使用线程池的好处是减少这些开销,解决资源不足的问题
JUC的线程架构
-
Executor
Executor是Java异步目标任务的执行者接口,其目标是执行目标任务,提供了execute()接口来执行已提交的Runnable执行目标实例。
-
ExecutorService
继承于Executor。它是Java异步目标任务的执行者服务接口,对外提供异步任务的接收服务。
-
AbstractExecutorService
是一个抽象类,它实现了ExecutorService接口,存在的目的是为了ExecutorService中的接口默认实现
-
ThreadPoolExecutor
线程池的实现类,继承于AbstractExecutorService抽象类
JUC线程池的核心实现类 提供了指定数量的可重用线程,所以使用线程需要很大的开销
-
ScheduleExcutorService
是一个接口可以完成延时和周期性任务的调度线程池的接口。其功能和Timer/TimerTask类似
-
ScheduledThreadPoolExecutor
-
Executors
静态工厂类,通过静态工厂方法返回线程池的实例对象
单线程化的线程池中的任务是按照提交次序顺序执行的
池中唯一线程的存活时间是无限的
当池中唯一线程正繁忙时,新提交的任务实例会进入内部的阻塞队列中,并且其阻塞队列是无界的
用例最后调用shutdown()方法来关闭线程池。
newFixedThreadPool创建“固定数量的线程池”
- 如果固定数量线程池没有达到“固定数量”,每次提交一个任务线程池就创建一个新的线程,直到线程达到线程池的固定数量。
- 线程池的大小一旦达到“固定数量”就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新的线程
- 在接受异步任务的执行目标实例时,如果池中所有的线程均处于繁忙状态,新任务会进入阻塞队列中(无界的阻塞队列)
固定数量线程池适用场景;需要任务长期执行的场景。固定数量的线程池的线程数量能比较稳定的保证一个数,避免频繁的回收线程和创建线程,固适用于处理CPU密集型任务,在CPU被工作线程长时间占用时,能确保尽可能少的分配线程
弊端:
- 内部使用无界队列来存放排队任 务,当大量任务超过线程池最大容量需要处理时,队列无限增大,使 服务器资源迅速耗尽。
newCachedThreadPool创建“可缓存线程池”
任务被拒绝有两种情况:
- 线程池已经被关闭
- 工作队列已满且maxmumPoolSize已满
线程池的拒绝策略
-
AbortPolicy:拒绝策略(线程池默认的策略)
使用该策略时,如果线程池队列满了,新任务就会被拒绝,并且 抛出RejectedExecutionException异常。该策略是线程池默认的拒绝 策略。
-
DiscardPolicy:抛弃策略
该策略是AbortPolicy的Silent(安静)版本,如果线程池队列满 了,新任务就会直接被丢掉,并且不会有任何异常抛出。
-
DiscardOldestPolicy:抛弃最老任务策略
抛弃最老任务策略,也就是说如果队列满了,就会将最早进入队 列的任务抛弃,从队列中腾出空间,再尝试加入队列。因为队列是队 尾进队头出,队头元素是最老的,所以每次都是移除队头元素后再尝 试入队。
-
CallerRunsPolicy:调用者执行策略
调用者执行策略。在新任务被添加到线程池时,如果添加失败, 那么提交任务线程会自己去执行该任务,不会使用线程池中的线程去 执行新任务。
-
自定义策略
如果以上拒绝策略都不符合需求,那么可自定义一个拒绝策略, 实现RejectedExecutionHandler接口的rejectedExecution方法即可。
线程池的五种状态
- RUNNING:线程池创建之后的初始状态,这种状态下可以执行任务
- SHUTDOWN:该状态下线程池不再接受新任务,但是会将工作队列中的任务执行完毕
- STOP:该状态下线程池不再接受新任务,也不会处理工作队列的剩余任务,并且将会中断所有工作线程。
- TIDYING:该状态下所有任务都已终止或者处理完成,将会 执行terminated()钩子方法。
- TERMINATED:执行完terminated()钩子方法之后的状态
线程池的转换规则:
- 线程池创建之后状态为RUNNING。
- 执行线程池的shutdown()实例方法,会使线程池状态从 RUNNING转变为SHUTDOWN。
- 执行线程池的shutdownNow()实例方法,会使线程池状态从 RUNNING转变为STOP。
- 当线程池处于SHUTDOWN状态时,执行其shutdownNow()方法 会将其状态转变为STOP。
- 执行完terminated()钩子方法之后,线程池状态从TIDYING 转变为TERMINATED。
优雅的关闭线程池主要涉及的方法有三个:
- shutdown:是JUC提供的一个有序关闭线程池的方法,此方 法会等待当前工作队列中的剩余任务全部执行完成之后,才会执行关 闭,但是此方法被调用之后线程池的状态转为SHUTDOWN,线程池不会 再接收新的任务
- shutdownNow:是JUC提供的一个立即关闭线程池的方法,此 方法会打断正在执行的工作线程,并且会清空当前工作队列中的剩余 任务,返回的是尚未执行的任务。
- awaitTermination:等待线程池完成关闭。在调用线程池的 shutdown()与shutdownNow()方法时,当前线程会立即返回,不会一直 等待直到线程池完成关闭。如果需要等到线程池关闭完成,可以调用 awaitTermination()方法。
使用Executors快捷创建线程池的潜在问题
-
创建固定数量线程池的潜在问题
主要存在于其workQueue上,其值为LinkedBlockingQueue(无 界阻塞队列)。如 果任务提交速度持续大于任务处理速度,就会造成队列中大量的任务 等待。如果队列很大,很有可能导致JVM出现OOM(Out Of Memory)异 常,即内存资源耗尽。
-
使用Executors创建“单线程化线程池”的潜在问题
潜在问题仍然存在于其workQueue属性上,该属性的值为 LinkedBlockingQueue(无界阻塞队列)。如果任务提交速度持续大于 任务处理速度,就会造成队列大量阻塞。如果队列很大,很有可能导 致JVM的OOM异常,甚至造成内存资源耗尽。
-
使用Executors创建“可缓存线程池”的潜在问题
(1)FixedThreadPool和SingleThreadPool 这两个工厂方法所创建的线程池,工作队列(任务排队的队列) 的长度都为Integer.MAX_VALUE,可能会堆积大量的任务,从而导致 OOM(即耗尽内存资源)。
(2)CachedThreadPool和ScheduledThreadPool 这两个工厂方法所创建的线程池允许创建的线程数量为 Integer.MAX_VALUE,可能会导致创建大量的线程,从而导致OOM。
线程池的好处:
- 降低资源消耗
- 提高响应速度
- 提高线程的可管理性
相关文章:
初尝并行编程
进程被分为后台进程和应用进程 大部分后台进程在系统开始运行时被操作系统启动,完成操作系统的基础服务功能。大部分应用进程由用户启动,完成用户所需的具体应用功能 进程由程序段、数据段、进程控制块三部分组成 程序段也被称为是代码段,…...
keepalived学习记录:对其vip漂移过程采用gdb跟踪
对其vip漂移过程采用gdb跟踪keepalived工具主要功能产生vip漂移过程两种情况gdb调试常用命令gdb调试时打到的函数栈(供学习参考)函数栈的图是本人理解下画的,不对请多指正 keepalived主要有三个进程,父进程是core进程,…...
51单片机串口通讯原理及程序源码-----day8
51单片机串口通讯原理及程序源码-----day8 1.定义单片机为TTL电平:高 5V 低 0V RS232电平: 计算机的串口高 -12V 低12V 所以计算机与单片机之间通讯时需要加电平转换芯片CH340T 、 MAX232。 2.通信分类: (1)并行通信通…...
mongodb入门到使用(下)
mongodb中常用命令操作一、用户操作二、创建用户三、数据库操作基本操作四、扩展操作五、集合操作一、用户操作 在mongo中使用mongodb都需要在admin数据库中操作。然后在使用下面的命令 use admin二、创建用户 db.createUser({"user":"imooc", #用户名&q…...
云HIS系统源码 医院his源码 云his源码
大型医院his系统源码 SaaS运维平台多医院入驻强大的电子病历完整文档 ,有演示 一、系统概述: 基层卫生健康云是一款满足基层医疗机构各类业务需要的健康云产品。该产品能帮助基层医疗机构完成日常各类业务,提供病患挂号支持、病患问诊、电子…...
朴素贝叶斯法学习笔记
频率派和贝叶斯派 频率派认为可以通过大量实验,从样本推断总体。比如假定总体服从均值为μ\muμ,方差为σ\sigmaσ的分布。根据中心极限定理,是可以通过抽样估算总体的参数的,而且抽样次数越多,对总体的估计就越准确。…...
vscode与C++安装与使用【不好用来骂我】
网上教程很多,但是都不太好用,这是我垃圾堆里淘金淘出来的教程: 安装软件 安装 Visual Studio Code: 你需要下载并安装 Visual Studio Code,可以在官网下载 https://code.visualstudio.com/download。 安装 C 扩展: 在 Visual S…...
C++11使用多线程(线程池)计算相似度实现性能优化
需求:图像识别中,注册的样本多了会影响计算速度,成为性能瓶颈,其中一个优化方法就是使用多线程。例如,注册了了3000个特征,每个特征4096个float。可以把3000个特征比对放到4个线程中进行计算,然…...
【测绘程序设计】——平面坐标转换
测绘工程中经常遇到平面坐标转换——比如,北京54(或西安80)平面坐标转换成CGCS2000平面坐标、工程独立坐标系平面坐标转换成CGCS2000平面坐标等,常用转换模型包括:①三参数法(2平移+1旋转);②四参数法(赫尔默特法,2平移+1旋转+1尺度);③六参数法(仿射变换法,2平移…...
五子棋的设计与实现
术:Java等摘要:五子棋是一种两人对弈的纯策略型棋类游戏,非常容易上手,老少皆宜。为了更好的推广五子棋,研究简单的人工智能方式,运用Java开发五子棋游戏。主要包含了人机对战,棋盘初始化&#…...
大数据项目软硬件选择
目录 一.技术选型 二.系统数据流程设计 三.框架版本选型 如何选择Apache/CDH/HDP版本...
redis数据结构的适用场景分析
1、String 类型的内存空间消耗问题,以及选择节省内存开销的数据类型的解决方案。 为什么 String 类型内存开销大? 图片 ID 和图片存储对象 ID 都是 10 位数,我们可以用两个 8 字节的 Long 类型表示这两个 ID。因为 8 字节的 Long 类型最大可以…...
同步、异步、全双工、半双工的区别
1、通讯 1.1 并行通讯 定义:一条信息的各位数据被同时传送的通讯方式称为并行通讯; 特点: 各个数据位同时发送,传送速度快、效率高,但有多少数据位就需要多少根数据线,因此传送成本高,并且只…...
ClickHouse 与 Amazon S3 结合?一起来探索其中奥秘
目录ClickHouse 简介ClickHouse 与对象存储ClickHouse 与 S3 结合的三种方法示例参考架构小结参考资料ClickHouse 简介ClickHouse 是一种快速的、开源的、用于联机分析(OLAP)的列式数据库管理系统(DBMS),由俄罗斯的Yan…...
【Spark分布式内存计算框架——Structured Streaming】1. Structured Streaming 概述
前言 Apache Spark在2016年的时候启动了Structured Streaming项目,一个基于Spark SQL的全新流计算引擎Structured Streaming,让用户像编写批处理程序一样简单地编写高性能的流处理程序。 Structured Streaming并不是对Spark Streaming的简单改进…...
【Windows】【Linux】---- Java证书导入
问题: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 无法找到请求目标的有效证书路径 一、Windows—java证书导入 1、下载证书到本地(以下…...
【Linux学习】菜鸟入门——gcc与g++简要使用
一、gcc/g gcc/g是编译器,gcc是GCC(GUN Compiler Collection,GUN编译器集合)中的C编译器;g是GCC中的C编译器。使用g编译文件时会自动链接STL标准库,而gcc不会自动链接STL标准库。下面简单介绍一下Linux环境下(Windows差…...
Cadence Allegro 导出Bill of Material Report详解
⏪《上一篇》 🏡《总目录》 ⏩《下一篇》 目录 1,概述2,Assigned Functions Report作用3,Assigned Functions Report示例4,Assigned Functions Report导出方法4.1,方法14.2,方法2B站关注“硬小二”浏览更多演示视频...
localStorage线上问题的思考
一、背景: localStorage作为HTML5 Web Storage的API之一,使用标准的键值对(Key-Value,简称KV)数据类型主要作用是本地存储。本地存储是指将数据按照键值对的方式保存在客户端计算机中,直到用户或者脚本主动清除数据&a…...
什么是DNS域名解析
什么是DNS域名解析?因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,得到该主机名对应的IP地址的过程叫做域名解析。正向解析:…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
【大模型】RankRAG:基于大模型的上下文排序与检索增强生成的统一框架
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构C.1 指令微调阶段C.2 排名与生成的总和指令微调阶段C.3 RankRAG推理:检索-重排-生成 D 实验设计E 个人总结 A 论文出处 论文题目:RankRAG:Unifying Context Ranking…...
【Java多线程从青铜到王者】单例设计模式(八)
wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本,sleep也是可以指定时间的,也就是说时间一到就会解除阻塞,继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒),wait能被notify提前唤醒…...
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...
k8s从入门到放弃之Pod的容器探针检测
k8s从入门到放弃之Pod的容器探针检测 在Kubernetes(简称K8s)中,容器探测是指kubelet对容器执行定期诊断的过程,以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...
【Redis】Redis 的持久化策略
目录 一、RDB 定期备份 1.2 触发方式 1.2.1 手动触发 1.2.2.1 自动触发 RDB 持久化机制的场景 1.2.2.2 检查是否触发 1.2.2.3 线上运维配置 1.3 检索工具 1.4 RDB 备份实现原理 1.5 禁用 RDB 快照 1.6 RDB 优缺点分析 二、AOF 实时备份 2.1 配置文件解析 2.2 开启…...
