服务端开发之Java备战秋招面试篇6-Java各种并发锁

news2024/12/28 23:22:52

努力了那么多年,回头一望,几乎全是漫长的挫折和煎熬。对于大多数人的一生来说,顺风顺水只是偶尔,挫折、不堪、焦虑和迷茫才是主旋律。我们登上并非我们所选择的舞台,演出并非我们所选择的剧本。继续加油吧!

目录

1、Java中主流锁分类体系介绍

2、乐观锁CAS原理刨析

 3、线程自旋、阻塞

4、synchronized原理分析

5、进程与线程的上下文切换


1、Java中主流锁分类体系介绍

下面看一下Java中锁的大体结构,根据存取数据是都锁住资源分为乐观锁与悲观锁。锁住资源失败,若不阻塞,可以使用自旋锁。当然还有无锁,偏向锁,轻量级锁,重量级锁,公平锁,非公平锁,可重入锁,非可重入锁,共享锁,排它锁。

乐观锁在获取数据的时候会加锁,悲观锁在获取数据时不加锁,只有在更新数据的时候判断有没有被其它线程更新。 

悲观锁会导致线程阻塞的问题,某一线程加锁使用资源,其它线程等待,也就是阻塞,等线程释放锁,cpu会唤醒阻塞的线程,线程再次去尝试获取锁。

乐观锁,本质上就是线程取数据不上锁,但是更新内存中的同步资源之前需要先判断资源是否被其它线程修改,若未修改,则获取同步资源,若已修改,则根据实现方法不同执行不同的操作。

CAS算法:是无锁算法,基于硬件原语实现的,在不使用锁的情况下实现多线程之间的变量同步,比如concurrent包中的原子类就是通过CAS算法实现了乐观锁。

2、乐观锁CAS原理刨析

如果想要并发更改主内存中的值,在更改的时候,比较线程1中得A值是否与主内存中得V值相等,若A==V,则线程1可以更改主内存中的值。假设线程2也想更改,如果A与V不相等,则会进行自旋,就是重新加载内存中的V值到线程栈中未A。一般有默认的自旋次数。线程不会阻塞,会一直占用CPU,可能导致CPU空转。

CAS可能存在的问题:ABA问题,就是变量其它线程更新无感知,通过在变量前加版本号的方式解决ABA问题,还有就是循环的开销比较大,以及只能保证一个共享变量的原子操作。

 
3、线程自旋、阻塞

自旋锁,是指锁被其它线程获取,那么当前线程不会阻塞,而是循环等待,不停地判断锁能否被成功获取,自旋直到获得锁才会退出。一直占用CPU,不会执行CPU状态的切换。

自适应自旋锁是自旋锁的改进,会根据上一次自旋的时间调整下一次自旋的时间。

4、synchronized原理分析

synchronized是JVM的内置锁,内部通过监视器锁实现,会被编译成为monitorenter和monitorexit,然后JVM判断是否加锁。

每个同步对象都有一个自己的监视器锁,需要判断对象能否拿到监视器锁,如果拿到监视器锁,才能进入同步块执行同步逻辑,否则需要进入同步队列等待。

锁升级过程:由无锁->偏向锁->轻量级锁->重量级锁。偏向锁:只有一个线程进入临界区访问同步块。轻量级锁:多线程竞争不激烈,同步块执行响应快。重量级锁:多线程竞争,同步块执行时间较长。 

对象的实例是存储在堆空间,对象的元数据存在方法区,对象的引用存储在栈空间。

对象存储包括两部分,对象头和对象的实际数据,随着锁的升级对象头中的数据是动态变化的。

5、进程与线程的上下文切换

首先看一下什么是内核态和用户态,程序运行在内核空间的状态称为内核态,运行在用户空间的状态称为用户态,用户态和内核态是操作系统的两种运行状态,划分为这两种空间状态主要是为了对应用程序的访问能力进行限制,防止应用程序随意进行一些危险的操作导致系统崩溃,比如设置时钟、内存清理,这些都需要在内核态下完成,如下:

① 内核态:内核态运行的程序可以不受限制地访问计算机的任何数据和资源,比如外围设备网卡、硬盘等。处于内核态的 CPU 可以从一个程序切换到另外一个程序,并且所占用的 CPU 不会发生抢占情况。
② 用户态:用户态运行的程序只能受限地访问内存空间,只能直接读取用户程序的数据,不允许访问外围设备网卡、硬盘等,用户态下所占有的 CPU 会被其他程序抢占,不允许独占。

  如果应用程序需要使用到内核空间的资源,则需要通过系统调用来完成,从用户空间切换到内核空间,直到完成相关的操作后再切合用户空间,两种状态间的切换,就涉及到 CPU 的上下文切换

那么如何发生CPU上下文切换的呢?我们先看两个概念:

  • ① CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。
  • ② 程序计数器,则是用来存储 CPU 正在执行的指令位置以及即将执行的下一条指令位置。

    CPU 寄存器和程序计数器都是 CPU 在运行任何任务时必须的依赖环境,因此也被叫做 CPU 上下文。而 CPU 上下文切换,就是先把前一个任务的 CPU 上下文保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

        回到系统调用的问题上,为了切换到内核态,需要先保存 CPU 寄存器中用户态的指令位置,然后更新 CPU 寄存器为内核态指令的新位置,最后跳转到内核态运行内核任务。而系统调用结束后,CPU 寄存器需要恢复原来保存的用户态,然后再切换到用户空间,继续运行进程。所以,一次系统调用的过程,其实是发生了两次 CPU 上下文切换。

进程都是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文切换不仅包括内核堆栈、寄存器等内核空间的状态,还包括了虚拟内存、栈、全局变量等用户空间的资源。因此进程的上下文切换就比系统调用导致的上下文切换多了一个步骤,在保存当前进程的内核状态和 CPU 寄存器之前,需要先把该进程的虚拟内存、栈等保存下来,等加载了下一个进程的内核态后,还需要刷新进程的虚拟内存和用户栈。
 

线程与进程最大的区别在于,进程是资源分配的基本单位,而线程是调度的基本单位,内核中的任务调度,实际上的调度对象是线程;同一个进程中的所有线程共享进程的虚拟内存、全局变量等资源。

        在处理多线程并发任务时,处理器会给每个线程分配CPU时间片,线程在各自分配的时间片内占用处理器并执行任务,当线程的时间片用完了,或者自身原因被迫暂停运行的时候,就会有另外一个线程来占用这个处理器,这种一个线程让出处理器使用权,另外一个线程获取处理器使用权的过程就叫做上下文切换。

         一个线程让出CPU处理器使用权,就是“切出”;另外一个线程获取CPU处理器使用权,就是“切入”,在这个切入切出的过程中,操作系统会保存和恢复相关的进度信息,而这个进度信息就是我们常说的“上下文”,也就是我们上文提到的 CPU寄存器以及程序计数器。

        这么一来,线程的上下文切换就可以分为两种情况:

① 前后两个线程属于同一个进程。此时,因为共享虚拟内存,所以在切换时,虚拟内存、全局变量这些资源就保持不动,只需要切换线程的私有数据,比如栈和寄存器等不共享的数据。
② 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程的上下文切换一样,不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态的修改
 

也可以参考这篇博客看看:java中的各种锁总结(简单全面版)_Mr.米斯特儿赵的博客-CSDN博客

多线程常见知识点总结(简单版)_Mr.米斯特儿赵的博客-CSDN博客

死锁的四个条件:互斥、不可剥夺、请求和保持、循环等待。

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

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

相关文章

wordpress 占用内容过高的解决方案

WordPress占用内存过高可能由多种因素引起,以下是一些可能的原因和解决方法: 主题和插件: WordPress的主题和插件是最常见的内存占用原因。确保使用的主题和插件是最新版本,并且只使用必需的插件。禁用不需要的插件,并…

【Linux】文件时间-ACM

文章目录文件时间-acmAccessChangeModify文件时间-acm 我们可以使用stat 文件名的方式查看对应的文件的时间信息 Access 表示文件最近一次被访问的时间 文件的访问 实际也就是文件的读取 实际操作中,文件的Access时间可能没有变化,这是因为在新的Linux内核中,Access时间不…

JavaScript 闭包的理解

1、概念 一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域 2、简单理解 闭包 内层函数 引用的外层函数变量 简单代码示例: function outer(){let i 1; // 被内层函数引用的变量function fn(){ // 内层函数console.log(i…

用javascript分类刷leetcode5.二分查找(图文视频讲解)

二分搜索 时间复杂度O(logn) 步骤&#xff1a; 从数组中间的元素开始&#xff0c;如果中间的元素正好是目标值&#xff0c;搜索结束如果目标值大于或小于中间的元素&#xff0c;则在大于或小于中间的元素的那一半继续搜索 代码模版 //二分查找伪代码模版 while (left <…

3.1 模拟栈+表达式求值+模拟队列+单调栈

模拟栈 题目链接 栈的数组模拟非常简单&#xff0c;不详细描述 设置一个指针指向栈顶第一个元素即可 STL中stack实现已经更新在STL_Stack #include<iostream> #include<string>using namespace std;const int N1e51; int m; string s; int stack[N]; int p;//指针…

Cartesi 2023 年 2 月回顾

2023年2月28日&#xff0c;通过ETH Denver和Cartesi的在线全球黑客马拉松一起开启黑客马拉松赛季!ETH Denver 正在热火朝天的进行着&#xff0c;我们正在为3月25日开始的首个全球在线黑客马拉松做准备。但这并不是本月发生的所有事情。我们在继续扩展和发展在全世界各地的社区&…

【软件测试】接口测试和接口性能测试,资深测试老鸟的总结......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 只会独立使用工具&a…

程序员必备!最值得收藏的宝藏网站大盘点

做为程序员&#xff0c;没有收藏点宝藏网站都说不过去。 除了常见的大家熟知的知乎、谷歌、b站、CSDN、掘金等&#xff0c;今天将介绍一些其他更加实用的宝藏网站&#xff0c;程序员小伙伴们可以按需收藏哦&#xff5e; 1.菜鸟教程&#xff1a;https://www.runoob.com/ 国内…

大数据处理技术导论(6) | Datawhale组队学习46期

文章目录1. hive 概述2. hive 与传统关系型数据库的对比3. hive 数据类型4. hive 数据模型5. hive 实战5.1 创建表5.2 修改表5.3 清空表、删除表5.4 其他命令项目地址 https://github.com/datawhalechina/juicy-bigdata&#xff0c;感谢项目团队的付出。本次主要学习 hive 相关…

web,h5海康视频接入监控视频流记录三(后台node取流)

前端vue&#xff0c;接入ws视频播放 云台控制 &#xff0c;回放预览&#xff0c;都是需要调对应的海康接口。相当于&#xff0c;点击时&#xff0c;请求后台写好的接口&#xff0c;接口再去请求海康的接口 调用云台控制是&#xff0c;操作一次&#xff0c;不会自己停止&#x…

元宇宙如何在未来5年影响你的业务

自新冠疫情暴发以来&#xff0c;虽然数字经济的和实体经济受到了严重的冲击和影响&#xff0c;但这也加速了元宇宙在全球的发展。区块链、数字资产和非同质化代币&#xff08;NFTs&#xff09;的兴起进一步推动了世界对元宇宙的需求。元宇宙被定义为用户可以在其中进行互动的虚…

HiveSQL一天一个小技巧:如何将分组内数据填充完整?

0 需求1 需求分析需求分析&#xff1a;需求中需要求出分组中按成绩排名取倒数第二的值作为新字段&#xff0c;且分组内没有倒数第二条的时候取当前值。如果本题只是求分组内排序后倒数第二&#xff0c;则很简单&#xff0c;使用row_number()函数即可求出&#xff0c;但是本题问…

Netty之io.netty.util.concurrent.Promise与io.netty.util.concurrent.Future初解

目录 目标 Netty版本 Netty官方API 三者之间的关系 基本使用方法 java.util.concurrent.Future io.netty.util.concurrent.Future io.netty.util.concurrent.Promise 目标 了解io.netty.util.concurrent.Promise与io.netty.util.concurrent.Future的基本使用方法。了解…

操作系统权限提升(二十四)之Linux提权-明文ROOT密码提权

系列文章 操作系统权限提升(十八)之Linux提权-内核提权 操作系统权限提升(十九)之Linux提权-SUID提权 操作系统权限提升(二十)之Linux提权-计划任务提权 操作系统权限提升(二十一)之Linux提权-环境变量劫持提权 操作系统权限提升(二十二)之Linux提权-SUDO滥用提权 操作系统权限…

Netty学习(二):线程模型

目录 一、线程模型基本介绍 二、传统阻塞IO服务模型 2.1 工作原理图 2.2 模型特点 2.3 问题分析 三、Reactor模式 3.1 完善传统阻塞I/O服务模型 3.2 Reactor模型原理图 3.3 Reactor模式中核心组成 3.4 Reactor模式分类 四、单 Reactor 单线程 4.1 原理图 4.2 方案说…

(二十一)操作系统-信号量机制2

文章目录一、知识总览二、知识点回顾三、信号量机制实现进程互斥四、信号量机制实现进程同步五、信号量机制实现前驱关系六、总结一、知识总览 二、知识点回顾 整型信号量&#xff1a;用一个整数型的变量作为信号量&#xff0c;用来表示系统中某种资源的数量。   记录型信号量…

4.5 正则表达式过滤查询数据

文章目录1. 概述2. 基本字符匹配3.LIKE关键字与正则表达式的区别4.进行OR匹配5.匹配几个字符之一6.匹配范围7.匹配特殊字符8.匹配多个实例9.定位符1. 概述 正则表达式用来匹配更加复杂的查询条件&#xff0c;例如你想从文件中提取电话号码&#xff0c;想从查找名字中间有数字的…

带你掌握webSocket 和 socket.io的基本用法

两者的作用和区别 作用&#xff1a;使得前后端可以随时地相互沟通。什么是互相沟通呢&#xff1f;像网络请求这种就是客户端向服务端的单向的沟通&#xff0c;当然&#xff0c;网络请求也可以实现双向的沟通&#xff0c;比如ajax 轮询&#xff0c;就是浏览器开个定时器不断的发…

Python虚拟环境(pipenv、venv、conda一网打尽)[通俗易懂]

一、什么是虚拟环境 1. 什么是Python环境 要搞清楚什么是虚拟环境&#xff0c;首先要清楚Python的环境指的是什么。当我们在执行python test.py时&#xff0c;思考如下问题&#xff1a; python哪里来&#xff1f;这个主要归功于配置的系统环境变量PATH&#xff0c;当我们在命…

山地车和公路车怎么选

公路车&#xff1a; 只能适应平坦的路面&#xff0c;骑行阻力小&#xff0c;速度快比较适合新手 山地车&#xff1a; 能适应所有路面&#xff0c;更注重操控性和舒适性 怎么选&#xff1f; 1、先决定用途 旅游&#xff1a;旅行车、山地车、 通勤&#xff1a;公路车 2、预…