再次加深理解Java中的并发编程

目录

一、线程、进程、程序

二、线程状态

三、线程的七大参数

四、lock与synchronized锁机制

一)、lock与synchronized锁区别

二)、synchronized锁原理

三)、Lock锁原理

五、synchronized锁升级原理

一)、锁升级基础知识

二)、锁升级过程有什么用?

三)、synchronized锁升级具体过程

六、Volatile底层原理(可见性和禁止指令重排序)

一)线程安全三要素

二)volatile关键字是如何保证可见性和有序性呢?

三)volatile关键字是线程安全的吗?


一、线程、进程、程序

1.进程: 我们把运行中的程序叫做进程,每个进程都会占用内存与CPU资源,进程与进程之间互相独立,例如360杀毒软件中运行中

2.线程: 线程就是进程中的一个执行单元,负责当前进程中程序的执行。一个进程可以包含多个线程。多线程可以提高程序的并行运行效率。360杀毒软件中的垃圾清理功能

3.程序:是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码,例如360杀毒软件

二、线程状态

1.新建(New):创建线程对象时

2.就绪(Runnable):线程调用start方法,有执行资格没有执行权

3.运行:当就绪状态时抢到cpu的执行权之后,进入运行状态

4.阻塞(Blocked):当获取锁失败后,进入阻塞状态

5.等待(Waiting):等待被notify()方法唤醒

6.休眠(sleep):休眠一段时间,时间到了之后,进入就绪状态。

7.终止(Terminated):线程死亡

注意1:调用start方法方可启动线程,而run方法只是thread类中的一个普通方法调用,还是在主线程里执行。

注意2:wait(long) 和 sleep(long) 的效果都是让当前线程暂时放弃 CPU 的使用权,进入阻塞状态

sleep是Thread的静态方法,而 wait()都是 Object 的成员方法,每个对象都有

sleep方法是暂停当前线程,相当于休眠一段时间,之后会自动唤醒,而wait()必须被notify 或者notifyall方法唤醒,不然会一直阻塞。

Wait会释放锁,sleep不会:wait方法的调用必须先获取wait对象的锁,而sleep则无此限制,wait方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃 cpu,但你们还可以用);但是如果在 synchronized代码块中执行,并不会释放对象锁(我放弃 cpu,你们也用不了),sleep方法执行后不会释放对象锁。

三、线程的七大参数

1.核心线程数(corePoolSize):表示保持活动状态的最小线程数。

2.最大线程数(maximumPoolSize):表示允许创建的最大线程数。

3.空闲时间(keepAliveTime):表示当线程数量超过核心线程数时,多余的空闲线程能够保持存活的时间。

4.阻塞队列(workQueue):表示用于存储等待执行的任务的阻塞队列。

5.单位(unit):表示空闲时间的单位,例如毫秒、秒等。

6.拒绝策略(rejectedExecutionHandler):表示当任务无法提交给线程池执行时采取的策略。

四、lock与synchronized锁机制

一)、lock与synchronized锁区别

1.语法层面:

1.1.synchronized是关键字,源码在jvm中,用c++ 语言实现

1.2.Lock 是接口,源码由jdk 提供,用java语言实现

2.释放锁机制:

        使用 synchronized 时,退出同步代码块锁会由jvm自动释放锁,比较被动而使用Lock时,需要手动调用unlock方法释放锁,否则可能会导致死锁等问题。

3.都支持可重入锁

        都可以用来控制多个线程访问共享资源的互斥性。都支持可重入锁机制,即同一个线程在已经获得锁的情况下能够再次获取该锁。

4.性能: 

        synchronized适用于简单线程同步场景,Lock适用于高并发场景下,拥有更好的性能和灵活性。

5.synchronized和lock如何保证线程安全?

        synchronized一般情况下通过修饰方法或代码块保证线程安全,而lock一般搭配unlock实现线程安全,lock和unlock中间放需要保证线程安全的代码。但为了避免lock死锁问题,一般将unlock放置于finally代码块中。


//控制方法
public synchronized void sync(){
}Object lock = new Object();
//控制代码块
public void sync(){
synchronized(lock){}Lock lock =new ReentrantLock();public void sync(){
lock.lock();//上锁
//TODO线程安全的代码
lock.unlock//释放锁,避免死锁}

二)、synchronized锁原理

        其主要原理是基于Java对象的内部锁,即监视器锁(Monitor Lock),确保在同一时刻只有一个线程可以访问被保护的代码块或方法。当一个线程尝试获取被synchronized关键字保护的资源时,如果该资源已被其他线程占用,该线程就会进入等待状态。占用资源的线程释放该资源时,等待队列中的线程会竞争获取该资源,并且只有一个线程会成功获取到该资源,其他线程继续等待。        

        synchronized关键字保证了可见性和原子性,可见性是通过JVM底层的内存屏障来实现的,原子性则是通过监视器锁的互斥性来实现的。在synchronized块内,线程获得了锁,它将会清空工作内存,从而使得该线程使用的变量能够从主内存中重新读取,同时也会把工作内存中的变量写回到主内存中。这样,其他线程就可以读取到最新的值,从而保证了可见性。

三)、Lock锁原理

        Lock的实现是基于Java的AbstractQueuedSynchronizer(AQS)框架的。Lock接口定义了多个获取和释放锁的方法,其中比较重要的是lock()和unlock()方法。当一个线程调用lock()方法获取锁时,如果锁未被占用,则该线程会占用锁并继续执行;否则,该线程会进入阻塞状态,直到锁被释放。当一个线程调用unlock()方法释放锁时,会通知等待队列中的其他线程继续尝试获取锁。

五、synchronized锁升级原理

一)、锁升级基础知识

1)偏向锁

        只有一个线程争抢锁资源的时候.将线程拥有者标识为当前线程。引入了偏向锁目的是来尽可能减少无竞争情况下的同步操作开销。当一个线程访问同步块并获取对象的锁时,会将锁的标记记录在线程的栈帧中,并将对象头中的Thread ID设置为当前线程的ID。此后,当这个线程再次请求相同对象的锁时,虚拟机会使用已经记录的锁标记,而不需要再次进入同步块。

2)轻量级锁(自旋锁)

        一个或多个线程通过CAS去争抢锁,如果抢不到则一直自旋。虚拟机会将对象的Mark Word复制到线程的栈帧中作为锁记录,并尝试使用CAS自旋操作尝试获取锁。如果CAS成功,则表示线程获取了轻量级锁,并继续执行同步块。如果CAS失败,说明有竞争,虚拟机会通过自旋等待其他线程释放锁。

3)重量级锁

        如果自旋等待不成功,虚拟机会将轻量级锁升级为重量级锁。在这种状态下,虚拟机会将线程阻塞,并使用操作系统的互斥量来实现锁的释放和获取。

        需要注意的是,锁的升级是逐级升级的过程,而不会存在降级。换句话说,一旦锁升级到更高级别,就不会再回到低级别。

二)、锁升级过程有什么用?

1)减少无竞争情况下的同步操作开销

        在多线程环境下,如果没有竞争,每个线程都可以安全地访问共享资源,无需进行同步操作。锁的升级过程中的第一阶段偏向锁(Biased Locking)就是为了在无竞争的情况下减少同步操作的开销。它通过记录线程ID来避免对锁的加锁和解锁操作,提高了单线程访问同步代码块时的性能

2)尽量避免线程切换的开销

        锁的升级过程中的第二阶段轻量级锁(Lightweight Locking)是为了减少线程切换的开销。它使用CAS操作来尝试获取锁,如果成功则可以继续执行同步块,无需线程切换;如果失败,则会进行自旋操作等待锁的释放。自旋操作避免了线程挂起和切换的开销,提高了多线程竞争时的性能

3)降低内存消耗

        锁的升级过程中的第二阶段轻量级锁使用对象头中的一部分位来存储线程ID和锁标记,不需要额外的内存存储锁的状态。相对于传统的重量级锁,它能够节省内存消耗。

4)提高系统吞吐量

        锁的升级过程可以使多个线程在无竞争情况下快速获取锁,避免了线程阻塞和等待的开销。这样,系统的吞吐量会更高,因为更多的线程可以并发地执行任务。

总而言之,锁的升级过程是为了提高多线程环境下的性能和吞吐量,减少同步操作的开销,并尽量避免线程切换的开销。Java虚拟机根据线程竞争的情况和锁的使用情况自动进行锁的升级和降级,以优化多线程程序的性能。

三)、synchronized锁升级具体过程

1)当只有一个线程去争抢锁的时候,会先使用偏向锁,就是给一个标识,说明现在这个锁被线程a占有。
2)后来又来了线程b,线程c,说凭什么你占有锁,需要公平的竞争,于是将标识去掉,也就是撤销偏向锁,升级为轻量级锁,三个线程通过CAS自旋进行锁的争抢(其实这个抢锁过程还是偏向于原来的持有偏向锁的线程).
3)现在线程a占有了锁,线程b,线程c一直在循环尝试获取锁,后来又来了十个线程,一直在自旋,那这样等着也是干耗费CPU资源,所以就将锁升级为重量级锁,向内核申请资源,直接将等待的线程进行阻塞。

六、Volatile底层原理(可见性和禁止指令重排序)

volatile 变量是一种比 sychronized 关键字更轻量级的同步机制。

一)线程安全三要素

原子性:一个操作或者多个操作,要么全部执行成功,要么全部执行失败。满足原子性的操作,中途不可被

中断。

可见性:多个线程共同访问共享变量时,某个线程修改了此变量,其他线程能立即看到修改后的值。

有序性程序执行的顺序按照代码的先后顺序执行。(由于JVM模型中允许编译器和处理器为了效率,进行指令重排序的优化。指令重排序在单线程内表现为串行语义,在多线程中会表现为无序。那么多线程并发编程中,就要考虑如何在多线程环境下可以允许部分指令重排,又要保证有序性)

二)volatile关键字是如何保证可见性和有序性呢?

保证可见性:当一个变量被volatile修饰后,JVM会把工作内存中的最新变量值强制刷新到主内存中,会导致其他线程中的本地缓存失效。这样,其他线程使用缓存时,发现本地工作内存中此变量失效,便会从主内存中获取,这样获取到的值就是最新的值,实现了线程之间可见性

保证有序性:通过编译器在生成字节码时,在指令序列中添加“内存屏障”来禁止指令重排序的,从而保证了有序性。(屏蔽在多线程环境下CPU的指令重排)

三)volatile关键字是线程安全的吗?

        因为volatile保证不了原子性,满足不了线程安全三要素,所以volatile不是线程安全的

值得说明的是,对 volatile 变量的单次读/写操作可以保证原子性的。如 long 和 double 类型变量,
但是并不能保证 i++这种操作的原子性,因为本质上 i++是读、写两次操作。在某些场景下可以代替 Synchronized。但是volatile 的不能完全取代 Synchronized 的位置,只有在一些特殊的场景下,才能适用 volatile。

总的来说,必须同时满足下面两个条件才能保证在并发环境的线程安全:
1、对变量的写操作不依赖于当前值(比如 i++),或者说是单纯的变量赋值(boolean 
flag = true)。
2、该变量没有包含在具有其他变量的不变式中,也就是说,不同的 volatile 变量之间,不
能互相依赖。只有在状态真正独立于程序内其他内容时才能使用 volatile。

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

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

相关文章

深度思考:雪花算法snowflake分布式id生成原理详解

雪花算法snowflake是一种优秀的分布式ID生成方案,其优点突出:它能生成全局唯一且递增的ID,确保了数据的一致性和准确性;同时,该算法灵活性强,可自定义各部分bit位,满足不同业务场景的需求&#…

java Web洗衣店管理系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 洗衣店管理系统是一套完善的web设计系统,对理解JSP java 编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发,数据库为Mysql5.0,使用…

API接口自动化测试框架搭建之需求整理、详细设计和框架设计!

​ 简介: API接口自动化测试框架搭建之需求整理、详细设计和框架设计 1 需求整理 1.1 实现目的 API接口自动化测试,主要针对http接口协议;便于回归测试;线上或线下巡检测试,结合持续集成,及时发现运行环…

嵌入式中逻辑分析仪的基本操作与实现

作为一名嵌入式软件/硬件工程师,要会使用各种仪表仪器,尤其示波器、逻辑分析仪, 这两个仪器可以监测各种数据线、信号线波形, 可以帮我们快速定位产品问题,缩短开发周期。 今天一口君安利一款非常不错的逻辑分析仪:kingst LA5016 这款仪器非常容易上手, 尤其在一些…

【滑动窗口】Leetcode 水果成篮

题目解析 904. 水果成篮 算法讲解 这道题的本质就是:寻找一段连续的区域(子数组),这一段连续的区域里面最多包含两种水果,因为有可能这一段连续的区域里面全是一种水果,比如:f(x) {1,1,1,1,…

Linux中安装JDK17.X

1、总体概述? 该操作方式适合centos或red hat环境 2.1、在线下载JDK安装包? 通过wget命令下载JDK17.X包 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 如果提示:没有wget命令就安装wget yum install w…

G35-2单螺杆泵

在现代工业流程中,流体输送是至关重要的一环。无论是石油化工、能源开采还是精细化工领域,高效率和可靠的泵送设备都是确保生产过程平稳运行的关键。在这样的背景下,G35-2单螺杆泵凭借其卓越的性能和广泛的应用性,成为了众多工业企…

答题小程序功能细节揭秘:如何提升用户体验和满足用户需求?

答题小程序功能细节体现 随着移动互联网的快速发展,答题小程序成为了用户获取知识、娱乐休闲的重要平台。一款优秀的答题小程序不仅应该具备简洁易用的界面设计,更应该在功能细节上做到极致,以提升用户体验和满足用户需求。本文将从题库随机…

SCI论文发表多长时间才可以被检索?

sci检索,是指发表的sci论文可以在web of science上查询到,是sci论文发表的最后一个步骤,建立在见刊的基础之上。那么,sci发表后多久可检索?没有统一标准,刊物不同,检索时间有差异。 一、SCI文章检索的注意…

深入解析AI大模型:原理、挑战与前景

前言 在现今技术飞速发展的时代,AI大模型学习已成为科技领域的研究热点。要想在这一领域取得突破,研究者需掌握扎实的数学基础、编程能力以及特定领域的业务知识。本文将深入剖析AI大模型的原理、挑战与前景,为读者提供有益的建议。 一、AI…

Mysql连接报错:1130-host ... is not allowed to connect to this MySql server如何处理

我用navicat连接我的阿里云服务器的mysql服务器的时候,出现了1130的报错。(mysql Server version: 5.7.42-0ubuntu0.18.04.1 (Ubuntu)) 我来记录一下这个原因,以及修改过程! 1.首先进入mysql -u root -p, mysql客户端…

FoFa 查询工具

FoFaX是一款使用Go编写的命令行FoFa查询工具、在支持FoFa查询规则上增加了Fx语法来方便使用者编写自己的规则、并且内置了一些常用的规则,除此之外还有联动其他安全产品在内的其他多个实用功能 ****fofax工具获取 https://github.com/xiecat/fofax 为了帮助大家更…

【微服务】配置Nacos管理SpringBoot配置文件(附解压包)

📝个人主页:哈__ 期待您的关注 一、什么是Nacos Nacos可以帮助我们配置和管理微服务,是阿里的一个开源产品,是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案。Nacos可以用来实现配置中心和服务注册中心。 …

FPGA高端图像处理开发板:鲲叔4EV,寄托了未来的一块开发板

目录 前言鲲叔4EV----高端FPGA图像处理开发板核心板描述底板描述配套例程源码描述配套服务描述开发板获取 前言 在CSDN写博客传播FPGA开发经验已经一年多了,帮助了不少人,也得罪了不少人,有的人用我的代码赢得了某些比赛、得到了心仪的offer…

基于视觉的机器人抓取——从物体定位、物体姿态估计到平行抓取器抓取估计——综述

综述 本文对基于视觉的机器人抓取进行了全面的综述。我们总结了基于视觉的机器人抓取过程中的三个关键任务,即物体定位、物体姿态估计和抓取估计。详细地说,对象定位任务包括无分类的对象定位、对象检测和对象实例分割。此任务提供输入数据中目标对象的…

腾讯也来电商掺一脚了?视频号小店或成2024年最大黑马!

大家好,我是电商小布。 当前的互联网时代下,电商无疑是最炙手可热的行业。 各种各样电商项目的出现,给了我们大家更多的机会选择,并从中来享受到流量至上的魅力。 腾讯旗下的视频号小店就是其中之一。 这个项目是依靠于视频号…

ios应用内支付

用uniapp开发iOS应用内支付 准备前端代码服务器端处理如果iOS支付遇到问题实在解决不了,可以联系我帮忙解决,前端后端都可以解决(添加的时候一定要备注咨询iOS支付问题) 准备前端代码 获取支付通道 (uni.getProvider) uni.getPr…

双非本,拿到美团测开实习了——经验分享

前言 最近是春招、暑期实习的高峰期,自己也凭借着持续的准备和一部分运气,较早拿到了美团的测开暑期实习。 以前接到美团的短信,都是外卖送达的通知,没想到自己有一天,也能收到offer录用的通知。虽然是测试开发的岗位…

【详细讲解语言模型的原理、实战与评估】

🌈个人主页:程序员不想敲代码啊🌈 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家🏆 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提…

使用PopLDdecay软件绘制LD衰减图

前记 PopLDdecay是一款用于进行种群遗传学和关联分析的软件。它可以在全基因组水平上进行基因型数据的相关性和衰减分析,帮助研究人员探索种群间的遗传差异和突变选择的模式。 使用PopLDdecay可以实现以下功能: 遗传距离的计算:可以计算遗…