java多线程

news2024/11/19 5:45:55

最近看了寒食君的java多线程的教程,感觉深受启发,做个笔记以后方便回忆。

寒食君的个人空间-寒食君个人主页-哔哩哔哩视频

java多线程

什么是线程模型?

JVM线程与操作系统线程之间存在着某种映射关系,这两种不同维度的线程之间的规范和协议,就是线程模型。

有一对一,一对多,多对多模型

什么是锁

在并发的环境下,当有多个线程去争抢同一个资源的时候,多个线程同时对资源进行了更改就会发生数据不一致的问题。为解决这个问题,通过一种抽象的锁去对资源进行绑定,即当一个线程持有锁的时候,其他线程必须等待。

悲观锁与乐观锁

乐观锁认为别人每次拿数据的时候不会修改数据,所以没有上锁,所以乐观锁也称为无锁。但是在更新的时候会判断别人有没有修改数据,比如CAS就是java中可观锁的一种实现方式。

悲观锁认为别人每次拿数据的时候都会修改数据,所以每次在读写数据的时候都会加上锁,比如Synchronized就是java中悲观锁的实现方式。

CAS

一句话:先比较再交换。比较什么呢:比较之前读到的值和当前时刻的读到的值发生变化没。发生变化了就不更改。不发生变化了就更改。

由于各个操作系统下的CAS操作都是原子的,比较和交换可以要么全部完成,要么全部不完成,这就使得CAS是安全的。

比如:Atomiclnteger,AQS就是通过CAS操作实现了无锁同步,仅仅在外层CAS加入一个循环实现自旋,进行多次的CAS操作来实现无锁同步。

Synchronized

Synchronized是一种对象锁,他是通过对象头中的Mark Word来区分锁的类型和锁与线程的对应关系。

在java6之前,Synchronized只有重量级锁,也就是通过Monitor来进行加锁操作,但是Monitor底层依赖操作系统Mutex Lock来实现,通过操作系统实现线程的切换需要将用户态(java线程就是用户线程)切换到操作系统的内核态。这是非常费时间的。所以依赖Monitor实现的锁也叫叫重量级锁。

在java6以后,java引入了“无锁”、“偏向锁”,“轻量级锁”,“重量级锁”的概念。

无锁:就是在多线程的环境下没有竞争,所以不需要进行同步保护,或者不适用操作系统级别的语言进行锁定,而是通过其他机制,比如CAS

偏向锁:就是说一个对象认识一个线程,只要这个线程过来,就直接把锁交过去。当有多个线程同时来争取对象,那么将变成轻量型锁。

轻量型锁(自旋锁):当一个对象被某个线程锁定,通过线程就通过 自选来等待,当其他线程释放锁了之后,当前线程就可以获取改对象了。自旋的数量不能超过一个,超过一个变为重量级锁。

重量型锁:如上。

Monitor

可以把他想象成一个只能容纳一个人的房间,当一个线程进入moitor,其他线程都只有等待

  1. Entry Set中聚集了一些想要进入Monitor的线程,它们处于waiting状态。

  2. 假设某个名为A线程成功进入了Monitor,那么它就处于active状态。

  3. 如果A线程执行途中,遇到一个判断条件,需要它暂时让出房间使用权,那么它将进入wait set,状态也 被标记为waiting

  4. 这时entry set中的其他线程就有机会进入Monitor,假设一个线程B成功进入并且顺利完成,那么 它可以通过notify的形式来唤醒wait set中的线程A,让线程A再次进入Monitor,执行完成后便退出。

Mark Word

就是一个表示锁状态和指针

AQS

一句话:即抽象队列同步器。核心思想我认为就是:当资源被某个线程占用的时候,将其他需要访问某个资源的线程加入到队列中等待。

为什么会出现AQS呢?就是当一个资源被占用的时候,其他线程需要访问这个资源,就需要通过不断的自旋来等待资源被释放,多个线程同时自旋是非常消耗cpu的资源的,如果把多个等待线程放入到一个队列之中,仅仅让头部的线程自旋,其他线程挂起,当头部的线程占到了资源去通知后续的节点,这样就可以大大的降低资源的利用率。

一个重要属性:state属性表示共享线程被多少个线程占有。因为AQS有两种模式,共享模式(e.g. CountDownLatch)和独占模式(e.g. ReentrantLock)。共享模式下某个资源可能被多个资源同时占有。

一个重要内部类:AQS通过Node类去封装线程。储存了线程对象、等待状态waitStatus前后节点的指针信息。因为AQS用到的是双向队列。

两个重要方法:tryAcquire(尝试获取锁),acquire(先尝试获取锁,获取不到就利用尾插法加入到等待队列之中)

addWaiter就是将node插入到队列之中,插入尾节点的时候用到了CAS操作。

acquireQueue就是去拿锁,如果失败,再去去判断线程是不是要被挂起。

注:通过waitStatus进行判断。只有队列的头节点释放了资源,头节点的next节点才有机会去拿锁。

waitStatus

0,节点初始化默认值或节点已经释放锁

cancelled为1,表示当前节点获取锁的请求已经被取消了

signal为-1,表示当前节点的后续节点需要被被唤醒

condition为-2,表示当前节点正在等待某一个Condition对象

propagate为-3,传递共享模式下锁释放状态

ReentrantLock

一句话:即可重入锁,ReentrantLock基于AQS实现,和他的名字一样,他的一个主要的特点就是可重入性,并实现了公平锁和非公平锁。

可重入性是指一个线程可以不用释放而重复获取一个锁n次,但是在释放的时候也要释放n次。

公平与非公平是指获取锁的时候有没有机会插队

ReentrantLock使用了setExclusiveOwnerThread,这个方法是将某一个线程设置为独占线程,所以他是悲观锁

CountDownLatch

一句话:CountDownLatch是基于AQS实现的,就是去帮助主线程再等待其他线程多个线程任务完成之后能继续执行。

我的理解是:子线程完成一个,倒计时减一,当倒计时变为0,阀门打开,主线程开始继续运行。倒计时指的是AQS的state属性。

 

ConcurrentHashMap

一句话:为了解决HashMap中线程不安全的问题,提出了ConcurrentHashMap,使用分段锁来锁定数据,也就是说一把锁只锁定一部分数据,大大减少了HashTable中锁的竞争问题。

ConcurrentHashMap可以认为是对HashTable的一种改进,因为HashTable只用了一把锁,锁住了所有数据,导致线程竞争资源特别严重。

Segment数组中的每个元素都持有一把锁,且指向一个哈希表即HashEntry数组。

segment数组和HashEntry数组的长度一定是2的整数次,这是如果数组的长度是2的整数,取模操作和移位操作是相同的,这样就大大减少了运行成本。而且在数组长度扩大的时候也不会出现排序变乱的问题。

构造函数:就是构建一个ConcurrentHashMap的数据结构,先确定Segment数组的长度,然后将每个Segment指向一个HashEntry数组,然后初始化HashEntry数组,感觉一个HashEntry数组类似一个HashMap。

put操作:就是通过hash运算找到Segment,然后通过Segment指针找到HashEntry数组,然后再进行hash运算,找到对应的HashEntry,然后查找HashEntry里面是不是存在该值,存在替换(这里用到了锁),不存在不利用头插法插入该元素

put操作中用到了ReentrantLock锁(调用了tryLock方法),每个HashEntrty数组都有一把锁,只有获得了这个锁才能插入值进去,不然就会有线程不安全的问题。

这里有个改进就是,如果没有获取到锁会先建立节点,再进行等待,这相当于是个预加载的机制。

ThreadPoolExecutor

一句话:为了让一个线程不反复的回收和新建,利用一个容器来管理线程。使一个线程在运行结束后不销毁去运行其他程序。这样做即减少开销又便于管理。

他的内部类Worker(Worker就是一个线程的包装类)继承于AQS,这是因为线程空闲的时候应该把他加入到一个AQS的队列之中等待,也就是将其中断,利用AQS机制减少自旋带来的性能减少。

threadPoolExecutor的执行流程

提交一个任务,如果池子存在空闲线程就直接拿去用

如果没有,就看核心线程是不是满了,没有满就创建线程

如果核心线程池满了就加入等待队列

如果等待队列满了,那就继续创建线程

如果线程的数量达到最大线程的数量,那就启用拒绝策略,不再接收

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

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

相关文章

SpringCloud微服务(十)——Hystrix服务降级熔断限流

Hystrix服务降级熔断限流 SpringCloud,已停更 前言 分布式系统面临的问题,复杂分布式体系结构中的应用程序,有数10个依赖关系(feign调用), 每个依赖关系在某些时候将不可避免地失败。低耦合就是微服务之间关系少。当…

pytorch初学笔记(十):神经网络基本结构之最大池化的使用

目录 一、最大池化:下采样 1.1 参数介绍 1.2 公式 二、最大池化的作用和目的 三、代码实战 3.1 题目要求 3.2 池化的具体实现 3.2.1 步骤 3.2.2 报错及其原因 3.2.3 ceil_mode不同运行的结果不同 3.2.4 完整代码 3.3 tensorboard可视化 一、最大池化&…

【强化学习论文合集】AAMAS-2022 强化学习论文 | 2022年合集(三)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

相控阵天线(六):直线阵列特殊综合方法(变形泰勒综合法、贝利斯综合法、伍德沃德抽样法)

目录简介变形泰勒综合法贝利斯综合法伍德沃德-劳森抽样法配相抵消法简介 阵列天线的综合问题是其分析的逆问题,即是在预先给定辐射特性(如方向图形状、副瓣电平等)的情况下,综合出阵列激励幅度和相位。其中特殊综合主要包括:左右副瓣电平不相…

关于Idea合并不同分支代码你怎么看

一、环境说明 1. IDEA版本 2020.1 2. git版本 2.33.0 二、整体合并 1. 软件开发中,在一次版本迭代过程中,大家可能会在同一个开发分支dev进行开发,同时开发不同功能 ,开发完以后需要自行合并到测试分支test,交给测试…

Feign高级实战-源码分析

目录参考导读什么是FeignFeign 和 Openfeign 的区别OpenFeign的启动原理在启动类申明EnableFeignClientsregisterDefaultConfigurationregisterFeignClientsregisterFeignClientgetTarget()创建一个代理对象HttpClientFeignLoadBalancerConfigurationOpenFeign 的工作原理动态代…

多策略协同改进的阿基米德优化算法及其应用(Matlab代码实现)

🍒🍒🍒欢迎关注🌈🌈🌈 📝个人主页:我爱Matlab 👍点赞➕评论➕收藏 养成习惯(一键三连)🌻🌻🌻 🍌希…

论文阅读:On the User Behavior Leakage from Recommender System Exposure

论文地址 Motivation: 现阶段对于用户行为的保护仅仅从用户端来考虑,比如用户的行为数据等。然而推荐系统是一个闭环的过程,即用户交互了物品,推荐系统根据用户的交互信息去推荐物品,用户也会根据推荐系统推荐的物品做…

[Java] 浅析rpc的原理及所用到的基本底层技术

文章目录前言阅读前须知rpc是什么?别的进程 vs 别的机器rpc的目的或是我们为什么需要rpc?实现rpc所涉及到的底层技术1. 通信技术(网络IO、Network IO)套接字(Socket)bio、nio与Netty2. 网络协议&#xff08…

【仿真建模】第三课:AnyLogic入门基础课程 - 多层建筑行人疏散仿真讲解

文章目录一、Agent类的概念二、行人疏散仿真2.1 仿真模型示意图2.2 具体实现步骤一、Agent类的概念 二、行人疏散仿真 2.1 仿真模型示意图 2.2 具体实现步骤 首先,新建模型 新建一个MyFloor1对象,代表第一个楼层 创建矩形墙,并放到原点…

专业数采软件DXP OPC Server售后问题解决方案

DeviceXPlorer OPC Server是一套实现工业自动化设备数据读取或发送的软件。它提供与制造车间中的控制设备(如 PLC、机床和机器人)的连接,支持200多种设备通讯协议,便捷的配置,快速实现设备联网采集。 在与设备通讯方面…

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计

🎀 精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

idea永久设置maven配置,新项目不用再设置

在这里设置就是永久的设置,新项目将使用该设置,maven的配置也在新项目和新模块创建的时候直接加载 英文的话,看位置大概也应该可以找到 点开后左上角搜索maven,找到如图maven的设置 主路径就是maven的安装包软件的路径 用户设置…

LeetCode 110平衡二叉树 257.二叉树的所有路径 404左叶子之和

文章目录110平衡二叉树c 代码实现python 代码实现257.二叉树的所有路径c代码实现python 代码实现404左叶子之和c 代码实现python 代码110平衡二叉树 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个…

http 知识整理

1. 启发式缓存 在不设置cache-control/expires的情况下,浏览器不会默认进入协商缓存。而是根据Date/LastModified去自动计算出合适的缓存时间。 计算方式为:(Date - LastModified) * n n:LM-Factor,处于[0,1]之间 2. 强制缓存 -…

Vue的模版代码与数据绑定方式

目录 模版代码 插值语法 指令语法 数据多层访问 vue模版语小结 数据绑定方式 模版代码 插值语法 插值语法就是使用{{xxx}}描述的 <div id"root">{{name}} </div> 指令语法 <div id"root"><a :href"school.url">…

lazada买家订单导出

下载安装与运行 https://www.yuque.com/webcrawl/handbook/mtad3q 用途与功能 所见即所得的导出自由选择导出项支持Excel、JSON两种方式导出自由排序Excel导出列顺序导出过程中有进度提示&#xff0c;用户可以随时提前中止 导出过程演示 选择lazada订单导出&#xff0c;开始…

linux内核整体架构

操作系统概念 操作系统属于软件范畴&#xff0c;负责管理系统的硬件资源。OS具备的功能&#xff1a;1.为应用程序提供执行环境。2.为多用户和应用程序管理计算机的硬件资源。3.虚拟化功能。4.支持并发。 宏内核与微内核架构 宏内核&#xff1a;所有的内核代码都编译成二进制…

基于JAVA的学生课程后台管理系统【数据库设计、源码、开题报告】

数据库脚本下载地址&#xff1a; https://download.csdn.net/download/itrjxxs_com/86427641 开学选好课是具备学术能力的首要表现。学生不能为了拿高分&#xff0c;只选简单课程&#xff0c;也没有必要为了显示出自己热衷自我挑战&#xff0c;奋不顾身地一头扎进高难度课程。在…

强化深度学习中利用时序差分法中的Sarsa算法解决风险投资问题实战(附源码 超详细必看)

需要源码请点赞关注收藏后评论区留下QQ~~~ 一、Sarsa算法简介 Sarsa算法每次更新都需要获取五元组&#xff08;S,A,R,S,A&#xff09;这也是该算法称为Sarsa的原因&#xff0c;每当从非终止状态进行一次转移后&#xff0c;就进行一次更新&#xff0c;但需要注意的是&#xff0…