【思维导图】并发编程

学习计划:将目前已经学的知识点串成一个思维导图。在往后的学习过程中,不断往思维导图里补充,形成自己整个知识体系。对于思维导图里的每个技术知识,自己用简洁的话概括出来, 训练自己的表达能力。

并发和并行的区别
并发是指多个任务交替执行。
并行是指多个任务同时被执行。 

线程与进程的区别
1、进程包含线程。
2、线程之间可以共享数据,比如说java线程之间共享堆内存和方法区里的数据。而进程之间是独立的,默认情况下是不共享数据的。
3、线程上下文切换开销小,而进程上下文切换开销大。(当线程状态改变时,就会出现线程上下文切换。线程上下文切换涉及到用户态与内核态的转变,因此开销较大。)
 


java线程与操作系统的线程的区别
java线程本质上就是操作系统的内核级线程,在一对一模型中每个java线程都会映射到一个内核级线程中。因此线程切换会导致用户态向内核态的转变,但不会因为线程阻塞而导致其他线程都阻塞。
而早期的java线程属于用户级线程,线程切换不会触发用户态的转变,但是如果有一个线程被阻塞,那么所有线程都会被阻塞。

线程生命周期
1、创建态(NEW)
线程被创建后但还没有调用start方法就是创建态。
2、运行态(RUNNABLE)
运行态包含就绪和运行两种状态。
3、阻塞态(BLOCKED)
当线程获取锁失败就会进入阻塞状态。
4、等待状态(WAITING)
调用wait方法就会进入等待状态,需要其他线程唤醒才能进入运行态。
5、超时等待状态(TIME_WAITING)
在等待状态的基础上增加了超时限制。当超时时间到达后,就会自动进入运行态。
6、终止态(DEAD)
线程执行run方法结束后或者异常退出后,线程就处于终止态了。
 


调用start方法和直接调用run方法的区别
调用start方法才表示启动一个线程并进入就绪态;而如果是调用run方法的话,并不会开启一个线程,而是会在main线程下执行这个run方法。 

创建多线程的几种方式
1、继承Thread类的方式
2、实现Runnable接口的方式
3、实现Callable接口
4、使用线程池创建线程

什么是线程安全
线程安全问题是指当多个线程同时读写一个共享资源并且没有任何同步措施时,导致出现脏数据或者其他不可预见的结果的问题。
 

如何保证线程安全
1、数据单线程内可见

2、只读对象

3、使用线程安全类

4、线程同步机制

5、共享变量可见性、禁止指令重排

synchronized和Lock的区别及使用场景
- 用法上分析:
1、synchronized锁是隐式锁,由jvm帮我们加锁释放锁;而Lock锁是显式的加锁和释放锁。所以synchronized锁更加便捷,但是因为它加锁和释放锁是固定的,因此Lock锁的会更加灵活。
- 功能上分析:
2、Lock锁支持中断,获取锁失败等待重新获取锁的线程如果被中断,会抛出异常,并且返回。而synchronized是如果线程获取锁失败会一直被阻塞,等待获取锁。
3、Lock锁支持超时获取锁,在等待重新获取锁过程中如果超过指定时间,则直接返回。这样可以避免死锁问题。而synchronized没有这样的功能。
4、Lock锁支持公平锁,比如ReentrantLock就实现了公平锁。而synchronized只有非公平锁。
适用场景:
1、synchronized适用于简单的需要加锁的逻辑中,而Lock适用于比较复杂的代码中。
2、如果有需要中断、保证公平的情景下应该选用Lock锁。
 


synchronized用法
synchronized可以修饰代码块或普通方法或静态方法。
 
synchronized锁静态方法和普通方法的区别
synchronized修饰静态方法,那么获取的对象锁就是当前类的Class对象。
synchronized修饰普通方法,那么获取的对象锁就是当前实例对象。

synchronized原理
synchronized底层是基于monitor实现的。使用synchronized时会尝试获取代码块或同步方法所属对象的monitor,而这底层是通过字节码指令monitorenter和monitorexit实现的。当执行monitorenter时,就会尝试获取monitor,只有monitor为0或同一个线程再次获取同一把锁则获取锁成功。只有获取成功才能执行代码块或同步方法里的代码。
 


synchronized怎么做到可重入的,说场景
当线程尝试获取锁时,判断出monitor的owner就是自己本身这个线程,那么会让monitor计数器继续+1,这样就实现了可重入。
 


synchronized锁升级过程
synchronized引入锁升级过程,是为了提高获取锁和释放锁的性能,毕竟在jdk1.6之前如果线程竞争没获取锁的话就会进入阻塞态,这需要进行内核态的转变,性能差。于是引入了偏向锁、量级锁的升级过程。偏向锁就是当一个线程想要获取锁时,会在对象头中存储这个线程id并且将对象头里的偏向锁标识设置为1,如果下次同一个线程想要再次获取同一把锁时,首轻先判断的就是对象头中的线程id是否与自己的相同,如果相同,则这个线程直接获取锁成功。这样就省去了CAS加锁的操作。而如果不同的线程想要获取这把锁,则会将这个偏向锁升级为轻量级锁。轻量级锁加锁过程就是CAS将对象头的mark word信息复制到线程的栈中,然后mark word里的指针指向锁记录。而如果CAS失败,则自旋尝试重新获取锁。而当线程竞争激烈时,就会升级为重量级锁。重量级锁就是一旦没有获取到锁,就被阻塞。
 


什么是悲观锁和乐观锁
悲观锁认为自己在使用数据时一定会有其他线程来修改数据,因此在获取数据前会先加锁,确保数据不会被其他线程修改。乐观锁认为自己在使用数据时不会有其他线程来修改数据,因此在读取数据时不会添加锁,只有修改数据前数据是否有被其他线程修改,如果没有其他线程修改,那么就放心大胆的修改数据,而如果数据被其他线程修改,那么自己就修改数据失败。

什么是CAS
CAS是实现乐观锁的一种算法。CAS能够在不使用锁的情况下,保证线程同步。
CAS就是首先读取数据,当要修改数据时会再次读取数据,检查数据是否有发生变化,如果数据没变化才能更新数据。
 


CAS有什么缺点,怎么解决
1、ABA问题
当更新数据前检查数据有没有发生变化,如果没有发生变化,但是这个数据可能经历了由A变成B然后变成A的过程。像这种CAS检查没有发生变化,但是实际上发生变化了。解决方法就为变量追加版本号,当变量发生变化时,就会有一个新的版本号。这样当CAS检查数据是否有变化时,不仅检查数据是否有发生变化,将版本号一起检查是否有发生变化。
2、循环时间开销大
如果CAS一直不成功,则会一直自旋,给CPU带来非常大的开销。
3、只能保证一个共享变量的原子操作
CAS只能保证一个共享变量进行原子操作,但是不支持多个共享变量的原子操作。这只能使用锁来保证。但也可以将多个变量放到一个对象里用CAS保证原子性。

哪些结构用了CAS
1、ReentrantLock的实现是通过使用CAS来获取锁。
2、AtomicInteger、AtomicLong、AtomicReference 和 AtomicBoolean 等类都通过 CAS 实现了原子性的加、减、更新等操作。
3、ConcurrentHashMap 在更新哈希桶中的元素时,使用 CAS 来避免锁的竞争,提高性能。

公平锁与非公平锁的区别
公平锁是指多个线程按照申请锁的顺序来获取锁,线程会被加入到一个队列中,只有队列中的第一个线程才能获取锁。而非公平锁是加锁时就直接尝试获取锁。非公平锁可能出现后申请锁先获取锁的场景,因此非公平锁可能出现饿死的问题。但是非公平锁可以减少唤醒线程的上下文切换的开销,整体效率更高。
 


怎么创建一个公平锁
使用ReentrantLock的有参构造器,传一个true构造的公平锁。
 
 


AQS是干什么的?AQS的原理?
AQS是一个java并发包里的一个抽象类,里面提供了关于构建锁的各种方法,比如ReentrantLock、Semaphore这些锁就是基于AQS实现的。我们也可以基于AQS自定义锁,我们只需要提供获取锁、释放锁逻辑,剩余的都交给AQS处理就行了。
AQS的原理就是维护了一个volatile修饰的state变量表示同步状态。然后通过CAS完成对state变量的修改。AQS还维护了一个队列用来存储获取锁失败的线程,这些线程在一个死循环里,只有当前驱结点是头节点才能尝试获取锁,因此队列里的线程会先被阻塞进入等待状态,直到前驱结点将其唤醒后,检查前驱结点是头结点后再尝试获取锁。这样可以避免不断死循环判断所带来资源浪费。
 
 

AQS里的node你了解吗?
node结构里包含了这个node所对应的线程id、线程状态、前驱节点、后继结点等信息。如果没有获取锁的线程会被包装成一个node结构存储在AQS维护的队列中。node结点的前驱结点的线程状态决定线程是否被阻塞,线程被阻塞后等待前驱结点的唤醒后重新获取锁,这样可以避免不断循环获取锁所带来资源浪费。

ReentrantLock是怎么实现可重入的?
(ReentrantLock中的tryAcquire方法体现可重入)
可重入性就是指同一个线程可以多次获取同一把锁。
ReentrantLock维护了一个state变量,尝试获取锁逻辑中,如果state变量为0,那么就可以获取锁,并将state设置为1,表示锁已经被这个线程占用了;如果state变量不为0,那么就会判断当前线程和持有这个锁的线程是不是同一个,如果是同一个,则会让state变量继续+1,然后返回true表示获取锁成功。如果锁被获取了n次,那么就需要释放n次,前n-1次释放返回的是false;只有当state被减为0时,才算真正释放成功,返回true。

synchronized和ReentrantLock的区别和使用场景
1、synchronized是隐式锁,由jvm加锁和释放锁;ReentrantLock是显式锁。因此synchronized使用其他比较便捷,但ReentrantLock更加灵活。
2、ReentrantLock支持中断,获取锁失败后等待获取锁期间可以被中断,而synchronized不支持中断,获取锁失败后会一直被阻塞直到锁被释放。
3、ReentrantLock支持超时获取锁,如果等待获取锁时间超过了指定时间会直接返回,而不是继续等待获取锁。
4、ReentrantLock支持公平锁和非公平锁,而synchronized只支持非公平锁。
创建线程池的方式
1)使用Executors类中提供的线程池。
2)自己使用ThreadPoolExecutor构造器创建一个线程池(自己new一个ThreadPoolExecutor对象)

线程池核心参数
1)核心线程数(corePoolSize)
2)线程池最大线程数(maximumPoolSize)
3)线程池除核心线程以外的线程的空闲存活时间(keepAliveTime)
4)阻塞队列(BlockingQueue<Runnable> workQueue)
5)线程工厂(ThreadFactory threadFactory)
6)拒绝策略(RejectedExecutionHandler handler)
线程池类型
1)fixed线程池,表示创建固定线程数量的线程池(Executors.newFixedThreadPool)
2)single线程池,创建只有一个线程的线程池(Executors.newSingleThreadExecutor)
3)Cached线程池,表示创建线程数可伸缩的线程池,最大线程数可以达到Integer.MAX_VALUE。
4)Schedule线程池,与Cached线程池的区别在于不回收空闲线程。 
 

自定义线程工厂
通过实现ThreadFactory接口实现自定义线程工厂,之所以推荐自定义线程工厂的原因在于,为线程指定有意义的名称,怎么指定?就是在重写newThread方法时,创建线程传入线程名称参数即可。

线程池处理任务流程
当要执行任务时,首先获取线程池里当前运行线程数,判断当前运行线程数是否大于等于核心线程数,如果当前运行线程数小于核心线程数,则会创建一个线程执行这个任务;如果当前工作线程数大于等于核心线程数,则会进入下一个流程,判断阻塞队列是否已满,如果没满,则将这个任务添加到阻塞队列中;如果阻塞队列已满,则会进入下一个流程,判断当前运行线程数是否大于等于最大线程数,如果当前运行线程数小于最大线程数,那么就会新建一个线程执行这个任务;反之,拒绝这个任务。(execute方法)
 


如果让线程池工作的话,需要Worker,Worker中存储什么信息
线程池里的线程用Worker类来实现。Woker类中有一个Thread字段和firstTask表示这个线程被start后执行的第一个任务。 这个线程执行完这个firstTask后就会循环从阻塞队列里获取任务执行。 

线程池拒绝任务方式 
1)AbortPolicy:默认情况下的拒绝策略就是丢弃这个任务并抛出异常
2)DiscardPolicy:丢弃这个任务,不做任何处理
3)DiscardOldestPolicy:抛弃队列中等待最久的任务,并执行当前任务。
4)CallerRunsPolicy:用调用者所在线程来执行任务。
5)我们也可以通过实现RejectedExecutionHandler接口自定义策略。比如说将拒绝的任务持久化到数据库中,等有余力时再处理这些未被处理的任务。

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

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

相关文章

【B站保姆级视频教程:Jetson配置YOLOv11环境(四)cuda cudnn tensorrt配置】

Jetson配置YOLOv11环境&#xff08;4&#xff09;cuda cudnn tensorrt配置 文章目录 0. 简介1. cuda配置&#xff1a;添加cuda环境变量2. cudnn配置3. TensorRT Python环境配置3.1 系统自带Python环境中的TensorRT配置3.2 Conda 虚拟Python环境中的TensorRT配置 0. 简介 官方镜…

【深度分析】DeepSeek 遭暴力破解,攻击 IP 均来自美国,造成影响有多大?有哪些好的防御措施?

技术铁幕下的暗战&#xff1a;当算力博弈演变为代码战争 一场针对中国AI独角兽的全球首例国家级密码爆破&#xff0c;揭开了数字时代技术博弈的残酷真相。DeepSeek服务器日志中持续跳动的美国IP地址&#xff0c;不仅是网络攻击的地理坐标&#xff0c;更是技术霸权对新兴挑战者的…

如何在数据湖中有效治理和管理“数据沼泽”问题,提高数据的可发现性和利用率?

在数据湖中有效治理和管理“数据沼泽”问题&#xff0c;提高数据的可发现性和利用率&#xff0c;需要从多个方面入手&#xff0c;包括数据治理、元数据管理、数据质量控制、安全性保障以及生命周期管理等。以下是具体的策略和方法&#xff1a; 1. 构建强大的数据治理框架 数据…

【4Day创客实践入门教程】Day3 实战演练——桌面迷你番茄钟

Day3 实战演练——桌面迷你番茄钟 目录 Day3 实战演练——桌面迷你番茄钟1. 选择、准备元件、收集资料2. 硬件搭建3.编写代码 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟…

Oracle Primavera P6自动进行进度计算

前言 在P6 Professional 有一个自动计划计算的选项&#xff0c;很多人不了解该设置如何使用&#xff0c;以及什么时候该启动这项配置。 详情 P6 Professional 默认为非自动进度计算。启用自动选项后&#xff0c;可以快速查看调度更改的效果。 ​ ​ 如图所示&#xff0c;当你…

DeepSeek-R1 论文解读 —— 强化学习大语言模型新时代来临?

近年来&#xff0c;人工智能&#xff08;AI&#xff09;领域发展迅猛&#xff0c;大语言模型&#xff08;LLMs&#xff09;为通用人工智能&#xff08;AGI&#xff09;的发展开辟了道路。OpenAI 的 o1 模型表现非凡&#xff0c;它引入的创新性推理时缩放技术显著提升了推理能力…

大模型GUI系列论文阅读 DAY4续:《Large Language Model Agent for Fake News Detection》

摘要 在当前的数字时代&#xff0c;在线平台上虚假信息的迅速传播对社会福祉、公众信任和民主进程构成了重大挑战&#xff0c;并影响着关键决策和公众舆论。为应对这些挑战&#xff0c;自动化假新闻检测机制的需求日益增长。 预训练的大型语言模型&#xff08;LLMs&#xff0…

LevelDB 源码阅读:写入键值的工程实现和优化细节

读、写键值是 KV 数据库中最重要的两个操作&#xff0c;LevelDB 中提供了一个 Put 接口&#xff0c;用于写入键值对。使用方法很简单&#xff1a; leveldb::Status status leveldb::DB::Open(options, "./db", &db); status db->Put(leveldb::WriteOptions…

【Proteus仿真】【51单片机】多功能计算器系统设计

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 联系作者 一、主要功能 1、LCD1602液晶显示 2、矩阵按键​ 3、加减乘除&#xff0c;开方运算 4、带符号运算 5、最大 999*999 二、使用步骤 基于51单片机多功能计算器 包含&#xff1a;程序&…

origin调整图像的坐标轴,修改坐标轴起始点,增量

接上一篇帖子&#xff0c;如果再修改数据之后或者当前的数据之间差距较小&#xff0c;怎么通过调整坐标轴来使数据之间的差距更明显&#xff0c;举个例子&#xff0c; 像下面这个图的entropy指标&#xff0c;都是介于6到9之间&#xff0c;如果y轴坐标都从0开始&#xff0c;使用…

Redis_Redission的入门案例、多主案例搭建、分布式锁进行加锁、解锁底层源码解析

目录 ①. Redis为什么选择单线程&#xff1f; ②. 既然单线程这么好,为什么逐渐又加入了多线程特性&#xff1f; ③. redis6的多线程和IO多路复用入门篇 ④. Redis6.0默认是否开启了多线程&#xff1f; ⑤. REDIS多线程引入总结 ①. Redis为什么选择单线程&#xff1f; ①…

ARM嵌入式学习--第十一天(中断处理 , ADC)

--中断的概念 中断是指计算机运行过程中&#xff0c;出现某些意外情况需主机干预时&#xff0c;机器能自动停止正在运行的程序并转入处理新情况的程序&#xff0c;处理完毕后又返回被暂停的程序继续运行 --CPU处理事情的方式 -轮询方式 不断查询是否有事情需要处理&#xff0c…

vue2项目(一)

项目介绍 电商前台项目 技术架构&#xff1a;vuewebpackvuexvue-routeraxiosless.. 封装通用组件登录注册token购物车支付项目性能优化 一、项目初始化 使用vue create projrct_vue2在命令行窗口创建项目 1.1、脚手架目录介绍 ├── node_modules:放置项目的依赖 ├──…

[ACTF2020 新生赛]BackupFile1

题目 翻译&#xff0c;尝试找出源文件&#xff01; 扫目录使用参数-e * python dirsearch.py -u http://0c3b21c0-d360-4baa-8b97-aa244f4c4825.node5.buuoj.cn:81/ -e * 最终扫描到一个文件名为&#xff1a;/index.php.bak的文件&#xff0c;把备份文件下载下来 源码 <?…

OPENPPP2 —— VMUX_NET 多路复用原理剖析

在阅读本文之前&#xff0c;必先了解以下几个概念&#xff1a; 1、MUX&#xff08;Multiplexer&#xff09;&#xff1a;合并多个信号到单一通道。 2、DEMUX&#xff08;Demultiplexer&#xff09;&#xff1a;从单一通道分离出多个信号。 3、单一通道&#xff0c;可汇聚多个…

DeepSeek-R1大模型本地部署及简单测试

目录 DeepSeek-R1大模型本地部署及简单测试背景我的测试环境模型参数选择适用场景参数规模 本地部署安装 DeepSeek-R1大模型本地部署及简单测试 背景 最近deepseek非常火, 要说2025年震惊科技圈的事件要数DeepSeek这个国产AI的横空出世&#xff0c;这是一款免费、开源且隐私优…

强化学习笔记(3)——基于值函数的方法和策略梯度方法

分为两大类方法&#xff1a; 基于值函数的方法&#xff08;Temporal Difference Methods, TD Methods&#xff09; 策略梯度方法&#xff08;Policy Gradient Methods&#xff09;。 二者不同之处&#xff1a; 通过值函数来间接表达隐式的策略&#xff0c;一个是直接迭代优化策…

Excel 技巧23 - 在Excel中用切片器做出查询效果(★★★)

本文讲如何在Excel中用切片器做出查询效果。 目录 1&#xff0c;在Excel中用切片器做出查询效果 1-1&#xff0c;Excel 中的切片器是什么&#xff1f; 1-2&#xff0c;用切片器做出查询效果 1&#xff09;&#xff0c;点击任一表格内单元格&#xff0c;按下CtrlA&#xff0…

leetcode——排序链表(java)

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&#xff1a; …

苯乙醇苷类化合物的从头生物合成-文献精读108

Complete pathway elucidation of echinacoside in Cistanche tubulosa and de novo biosynthesis of phenylethanoid glycosides 管花肉苁蓉中松果菊苷全生物合成途径解析及苯乙醇苷类化合物的从头生物合成 摘要 松果菊苷&#xff08;ECH&#xff09;是最具代表性的苯乙醇苷…