掌握了java锁的原理机制后其实变得很简单,难的是运用到各种业务的场景

详解ReentrantLock---可重入锁(小白易懂) ReentrantLock是可重入的互斥锁,虽然具有与synchronized相同功能,但是会比synchronized更加灵活(具有更多的方法)。ReentrantLock底层基于AbstractQueuedSynchronizer实现 阅读详情

synchronized


java的对象布局
1、对象头---大小固定---3*4=12byte
2、java对象的实例数据---大小不固定---变量数据类型所占大小
3、数据对齐---64bit JVM虚拟机要求对象大小必须是8byte的整数倍


对象头由什么组成
Mark Word --- 64bit
Class Metadata Address --- 32bit/64bit


对象状态

1.无状态 --- new出来的时候
2.偏向锁
3.轻量级锁
4.重量级锁
5.gc标记


synchronized底层工作的原理
synchronized优化原理

synchronized和lock


Java中有两种加锁的方式:一种是用synchronized关键字,另一种是用Lock接口的实现类。
synchronized是Java语言内置的关键字,而Lock是一个接口,这个接口的实现类在代码层面实现了锁的功能

Lock接口

实现

WriteLock类

ReadLock类

ReentrantLock类

ReadWriteLock接口(工厂)

静态内部类

实现

ReentrantReadWriteLock类(工厂)


悲观锁与乐观锁

悲观锁(Pessimistic Lock), 就是很悲观,每次去拿数据的时候都认为别人会修改。所以每次在拿数据的时候都会上锁。这样别人想拿数据就被挡住,直到悲观锁被释放。
乐观锁(Optimistic Lock), 就是很乐观,每次去拿数据的时候都认为别人不会修改。所以不会上锁!但是如果想要更新数据,则会在更新前检查在读取至更新这段时间别人有没有修改过这个数据。如果修改过,则重新读取,再次尝试更新,循环上述步骤直到更新成功(当然也允许更新失败的线程放弃操作)。
悲观锁阻塞事务,乐观锁回滚重试,它们各有优缺点,不要认为一种一定好于另一种。像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适


乐观锁的基础——CAS

Compare-and-Swap,即比较并替换
1、比较:读取到了一个值A,在将其更新为B之前,检查原值是否仍为A(未被其他线程改动)。
2、设置:如果是,将A更新为B,结束。如果不是,则什么都不做。
上面的两步操作是原子性的,可以简单地理解为瞬间完成,在CPU看来就是一步操作。
乐观锁其实不是“锁”,它仅仅是一个循环重试CAS的算法而已!


自旋锁

所谓自旋,说白了就是一个 while(true) 无限循环。
synchronized锁升级:偏向锁 → 轻量级锁 → 重量级锁
synchronized会从无锁升级为偏向锁,再升级为轻量级锁,最后升级为重量级锁;这里的轻量级锁就是一种自旋锁。


初次执行到synchronized代码块的时候,锁对象变成偏向锁(通过CAS修改对象头里的锁标志位),字面意思是“偏向于第一个获得它的线程”的锁。执行完同步代码块后,线程并不会主动释放偏向锁。当第二次到达同步代码块时,线程会判断此时持有锁的线程是否就是自己(持有锁的线程ID也在对象头里),如果是则正常往下执行。由于之前没有释放锁,这里也就不需要重新加锁。如果自始至终使用锁的线程只有一个,很明显偏向锁几乎没有额外开销,性能极高。
一旦有第二个线程加入锁竞争,偏向锁就升级为轻量级锁(自旋锁)。这里要明确一下什么是锁竞争:如果多个线程轮流获取一个锁,但是每次获取锁的时候都很顺利,没有发生阻塞,那么就不存在锁竞争。只有当某线程尝试获取锁的时候,发现该锁已经被占用,只能等待其释放,这才发生了锁竞争。


在轻量级锁状态下继续锁竞争,没有抢到锁的线程将自旋,即不停地循环判断锁是否能够被成功获取。获取锁的操作,其实就是通过CAS修改对象头里的锁标志位。先比较当前锁标志位是否为“释放”,如果是则将其设置为“锁定”,比较并设置是原子性发生的。这就算抢到锁了,然后线程将当前锁的持有者信息修改为自己。
长时间的自旋操作是非常消耗资源的,一个线程持有锁,其他线程就只能在原地空耗CPU,执行不了任何有效的任务,这种现象叫做忙等(busy-waiting)。如果多个线程用一个锁,但是没有发生锁竞争,或者发生了很轻微的锁竞争,那么synchronized就用轻量级锁,允许短时间的忙等现象。这是一种折衷的想法,短时间的忙等,换取线程在用户态和内核态之间切换的开销。
显然,此忙等是有限度的(有个计数器记录自旋次数,默认允许循环10次,可以通过虚拟机参数更改)。如果锁竞争情况严重,某个达到最大自旋次数的线程,会将轻量级锁升级为重量级锁(依然是CAS修改锁标志位,但不修改持有锁的线程ID)。当后续线程尝试获取锁时,发现被占用的锁是重量级锁,则直接将自己挂起(而不是忙等),等待将来被唤醒
一个锁只能按照 偏向锁、轻量级锁、重量级锁的顺序逐渐升级(也有叫锁膨胀的),不允许降级。


可重入锁(递归锁)

允许同一个线程多次获取同一把锁
比如一个递归函数里有加锁操作,递归过程中这个锁会阻塞自己吗?如果不会,那么这个锁就是可重入锁(因为这个原因可重入锁也叫做递归锁)
Java里只要以Reentrant开头命名的锁都是可重入锁,而且JDK提供的所有现成的Lock实现类,包括synchronized关键字锁都是可重入的。


公平锁、非公平锁

如果多个线程申请一把公平锁,那么当锁释放的时候,先申请的先得到,非常公平。显然如果是非公平锁,后申请的线程可能先获取到锁,是随机或者按照其他优先级排序的
对ReentrantLock类而言,通过构造函数传参可以指定该锁是否是公平锁,默认是非公平锁。一般情况下,非公平锁的吞吐量比公平锁大,如果没有特殊要求,优先使用非公平锁。
对于synchronized而言,它也是一种非公平锁,但是并没有任何办法使其变成公平锁。


可中断锁

可中断锁,字面意思是“可以响应中断的锁”。
Java并没有提供任何直接中断某线程的方法,只提供了中断机制。
中断机制:线程A向线程B发出“请你停止运行”的请求(线程B也可以自己给自己发送此请求),但线程B并不会立刻停止运行,而是自行选择合适的时机以自己的方式响应中断,也可以直接忽略此中断。也就是说,Java的中断不能直接终止线程,而是需要被中断的线程自己决定怎么处理
如果线程A持有锁,线程B等待获取该锁。由于线程A持有锁的时间过长,线程B不想继续等待了,我们可以让线程B中断自己或者在别的线程里中断它,这种就是可中断锁
在Java中,synchronized就是不可中断锁,而Lock的实现类都是可中断锁


读写锁、共享锁、互斥锁

读写锁其实是一对锁,一个读锁(共享锁)和一个写锁(互斥锁、排他锁)
如果我读取值是为了更新它(SQL的for update就是这个意思),那么加锁的时候就直接加写锁,我持有写锁的时候别的线程无论读还是写都需要等待;如果我读取数据仅为了前端展示,那么加锁时就明确地加一个读锁,其他线程如果也要加读锁,不需要等待,可以直接获取(读锁计数器+1)。


读写锁是悲观锁策略

我们在Java里使用的各种锁,几乎全都是悲观锁。synchronized从偏向锁、轻量级锁到重量级锁,全是悲观锁。JDK提供的Lock实现类全是悲观锁。其实只要有“锁对象”出现,那么就一定是悲观锁。因为乐观锁不是锁,而是一个在循环里尝试CAS的算法。

 

 

Java中的锁优化 锁优化是提高程序并发性能的关键手段,包括使用合适的锁类型如读写锁、可重入锁以适应不同场景;减小锁粒度,将锁作用范围限制在小范围代码或数据上以减少锁竞争;锁分离,将不同功能或数据用不同锁管理以避免不必要竞争;锁粗化,合并细小锁减少请求释放次数但需注意锁竞争;使用乐观锁,基于版本号控制并发,适合写少读多场景;以及使用无锁算法,通过原子操作、CAS等保证数据正确性,适合高并发低延迟场景。 阅读详情

相关推荐

自动驾驶——最优控制算法(LQR)工程化总结

到近段时间,真正在我们的控制器上运行最优控制算法(LQR),一步一个脚印,从开始只是知道其“控制理论”的阶段、再到对着一堆网上的资料和公式一筹莫展不知何着手、再到初步实现了LQR算法的开发(但是使用的扭矩环控制,控制的不好,而且由于各种原因被delay,迟迟无法落地),直到大上个星期,泊车平台有此LQR开发需求,又重新了开始了算法的研发,用时一个周时间完成了算法开发,然后再用一个周时间进行实车最优控制算法验证与调试,取得了很大的进展,由于执行器是转角控制的,这无疑少了很多的工作量。

qq_40464599的博客 2787

什么叫可重入锁

可重入性:就是一个线程不用释放,可以重复的获取一个锁n次,只是在释放的时候,也需要相应的释放n次。(简单来说:A线程在某上下文中或得了某锁,当A线程想要在次获取该锁时,不会应为锁已经被自己占用,而需要先等到锁的释放)假使A线程即获得了锁,又在等待锁的释放,就会造成死锁。 注意:synchronized和reentrantlock都是可重入锁 synchronized: 无需释放锁,synchronized会自动释放锁 public static void main(String[] arg

爪哇人的博客 1万+

零基础手把手教你做FMEDA

本文通过分步骤手把手来教大家具体如何做FMEDA,希望对工作中要做FMEDA的童鞋有帮助。对于工作当中用不到FMEDA的童鞋,也可以作为科普知识,更好地了解一下FMEDA及硬件功能安全。

NewCarRen的博客 9926

什么是可重入锁(递归锁)

当一个线程已经获得了锁,但在持有锁的代码块中又调用了另一个需要同样锁的方法时,如果使用非可重入锁,线程会因为无法再次获得同一个锁而陷入死锁状态。通过调用lock()方法获取锁,再调用unlock()方法释放锁,可以实现多次获取和释放同一个锁的操作。在存款(deposit)和取款(withdraw)方法中,首先使用lock.lock()获取锁,然后执行相应的操作,最后使用lock.unlock()释放锁。可重入锁(Reentrant Lock),也称为递归锁,是一种支持同一个线程多次获取同一个锁的锁机制。

Li2992673708的博客 4070

vue引入使用腾讯地图

// 引入鹅厂地图 initMap(lat = 0.0000000, lng = 0.0000000) { // 定义地图中心点坐标- var center = new TMap.LatLng(lat, lng) // 定义map变量,调用 TMap.Map() 构造函数创建地图 map = new TMap.Map(document.getElementById('txMapBox'), { center: center, // 设.

LiangRZ 4536

SAP 创建PO时提示“不能确定任何组件”

SAP 创建委外加工的PO时提示“不能确定任何组件” 而如果BOM已经创建了,但还是提示该错误保存。 解决办法:1. BOM selection 未配置好; 2. 由于Purchasing prosessing time的设置,如果PO中的delivery time - Purchasing prosessing time是过去的日期,那么会找不到BOM,BOM的有效期需早 于PO审批的有效期。 3. BOM未...

willieyuan的博客 6116

什么是可重入,什么是可重入锁? 它用来解决什么问题?

从早期的经典 I/O 到后来引入的 NIO(New Input/Output),Java 提供了多种方式来处理文件、网络等数据流。假设我们使用的是非可重入锁(如早期的 synchronized 键),当 outerMethod 获取锁后,innerMethod 再次尝试获取锁时会导致死锁,因为锁已经被当前线程持有。Java 的经典 I/O 模型(也称为阻塞 I/O)是基于流(Stream)的。可重入锁主要用于解决多线程环境下的资源竞争问题,同时避免因锁的不可重入性导致的死锁问题。

2301_78714573的博客 2617

Python 爬虫实战:拼多多商品评论情感分析(含词云生成与差评预警)

在电商行业竞争日益激烈的当下,商家对商品评论的分析需求愈发迫切。通过 Python 爬虫收集拼多多商品评论,并结合情感分析、词云可视化及差评预警技术,商家可精准洞察消费者反馈,优化商品与服务。本文将深度剖析从爬虫搭建到数据挖掘的关键环节,助力读者构建全流程电商评论分析系统。

yansideyucsdn的博客 1450

多线程(五)可重入锁、读写锁

ReentrantLock、ReentrantReadWriteLock

HK的博客 3418

Fast-Lio2代码及论文解析2

点云数据频率较低而IMU为高频数据。

努力努力努力 2278

YOLOv12超参数智能优化:基于内置Ray Tune的自动化调优实战指南

购买即可解锁300+YOLO优化文章,并且还有海量深度学习复现项目,价格仅需两杯奶茶的钱,别人有的本专栏也有! 目标检测模型的性能瓶颈往往源于超参数配置不当。传统手动调优方式不仅耗时耗力,且难以找到全局最优解。YOLOv12集成的Ray Tune框架为解决这一难题提供了完整方案,通过分布式异步优化算法,可实现超参数搜索效率的指数级提升。实际测试表明,采用Ray Tune自动调优的YOLOv12模型,在COCO数据集上mAP指标平均提升3.8%,收敛速度加快2.1倍。在VisDrone无人机数据集上的跨域测试

LXY_LOVE36的博客 118

精通Java并发锁机制:24种锁技巧+业务锁匹配方案

在 Java 并发编程中,锁是确保线程安全、协调多线程访问共享资源的关键机制。从基本的 `synchronized` 同步关键字到高级的 `ReentrantLock`、读写锁 `ReadWriteLock`、无锁设计如 `AtomicInteger`,再到复杂的同步辅助工具如 `CountDownLatch`、`CyclicBarrier` 和 `Semaphore`,每种锁都针对特定的并发场景设计,以解决多线程环境下的同步问题。`StampedLock` 提供了乐观读锁和悲观写锁的选项,而 `Concu

肖哥弹架构博客 3618

pymol 动画简单制作,gif、mp4导出

参考: https://www.youtube.com/watch?v=G77K9Lro8js1、直接Movie下Program下,Camera Loop下Nutate下选择,这里选择30degover4 sec;如果要动画过渡自然,可以在这4sec后面再Append 1sec;如果需要两个视角,既可以再把窗口蛋白定位到比如配体,不用管中间过程怎么定位过去配体,再Program下,Camera Loop下Nutate下选择,这里选择30degover4 sec添加;最后如果要整体形成个循环播放,可以在这4s

weixin_42357472的博客 8435

精通Java并发锁机制:24种锁技巧+业务锁匹配方案(第二部分)

在 Java 并发编程中,锁是确保线程安全、协调多线程访问共享资源的关键机制。从基本的 `synchronized` 同步关键字到高级的 `ReentrantLock`、读写锁 `ReadWriteLock`、无锁设计如 `AtomicInteger`,再到复杂的同步辅助工具如 `CountDownLatch`、`CyclicBarrier` 和 `Semaphore`,每种锁都针对特定的并发场景设计,以解决多线程环境下的同步问题。`StampedLock` 提供了乐观读锁和悲观写锁的选项,而 `Concu

肖哥弹架构博客 1811

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

精通Java并发锁机制:24种锁技巧+业务锁匹配方案(第一部分)

在 Java 并发编程中,锁是确保线程安全、协调多线程访问共享资源的关键机制。从基本的 `synchronized` 同步关键字到高级的 `ReentrantLock`、读写锁 `ReadWriteLock`、无锁设计如 `AtomicInteger`,再到复杂的同步辅助工具如 `CountDownLatch`、`CyclicBarrier` 和 `Semaphore`,每种锁都针对特定的并发场景设计,以解决多线程环境下的同步问题。`StampedLock` 提供了乐观读锁和悲观写锁的选项,而 `Concu

肖哥弹架构博客 1569

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

java中各类锁的机制详细解析(全)

目录前言1. 乐观锁与悲观锁2. 公平锁与非公平锁3. 可重入锁4. 读写锁(共享锁与独占锁)5. 互斥锁6. 自旋锁7. 无锁 / 偏向锁 / 轻量级锁 / 重量级锁 前言 总结java常见的锁 区分各个锁机制以及如何使用 使用方法 锁名 考察线程是否要锁住同步资源 乐观锁和悲观锁 锁住同步资源后,要不要阻塞 不阻塞可以使用自旋锁 一个线程多个流程获取同一把锁 可重入锁 多个线程公用一把锁 读写锁(写的共享锁) 多个线程竞争要不要排队 公平锁与非公平锁 具体其他补充还可

码农研究僧的博客 7815

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

java锁的底层原理

知识整理 Synchronized 内置锁,JVM级别 使用 底层 锁升级过程、CAS操作的缺点【替换线程和copy mw】 优化 代码优化:同步代码块、减少锁粒度、读锁并发 JDK自带 偏置锁、轻量级锁(CAS操作)、自适应自旋、锁粗化、锁消除 Volatile 概念:非阻塞可见性、禁止指令重排序* 与syn区别: 无法实现原子操作、使用场景--单...

大数据 1万+

公平锁与非公平锁的深入剖析与Java实现

本文深入剖析了公平锁与非公平锁的概念、业务场景、历史背景、功能点以及底层原理,并使用Java代码进行了模拟实现。通过对比两者的差异,我们可以更好地理解它们在不同场景下的适用性和性能特点。在实际应用中,我们应根据具体需求选择合适的锁实现方式,以确保系统的正确性和高效性。

喜欢猪猪 1185

【java并发编程】底层原理——锁分类和java锁机制

一、什么是锁? 在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制。锁旨在强制实施互斥排他、并发控制策略。 锁通常需要硬件支持才能有效实施。这种支持通常采取一个或多个原子指令的形式,如"test-and-set", "fetch-and-add" or "compare-and-swap"”。这些指令允许单个进程测试...

Wonder ZH 5470

简单了解下Java中锁的概念和原理

Java的锁通过java代码实现,go语言的锁通过go实现,python语言的锁通过python实现。它们都实现的什么呢?这部分就是锁的定义和设计模式、算法、原理等一些理论上的东西。

欢迎关注公众号“雨林寻北”,添加个人微信codetrend(备注技术)。 976

Java并发机制及锁的实现原理

Java并发机制及锁实现原理

void 2万+

Java面试-MySQL 锁机制:行锁、表锁、间隙锁、临键锁

《MySQL锁机制全解析:从行锁到临键锁》摘要 本文系统讲解了MySQL的锁机制,通过生动类比(如"排队上厕所")解释锁的作用。主要内容包括:表锁(整表锁定)、行锁(单行记录锁定)、间隙锁(防止幻读的范围锁定)、临键锁(行锁+间隙锁组合)以及协调锁冲突的意向锁。文章通过SQL示例演示了各种锁的工作场景,并分析了锁兼容性矩阵。最后指出锁机制是数据库在并发控制与性能之间的平衡艺术,理解锁对优化数据库性能至关重要。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

精通Java并发锁机制:24种锁技巧+业务锁匹配方案(第三部分)

在 Java 并发编程中,锁是确保线程安全、协调多线程访问共享资源的关键机制。从基本的 `synchronized` 同步关键字到高级的 `ReentrantLock`、读写锁 `ReadWriteLock`、无锁设计如 `AtomicInteger`,再到复杂的同步辅助工具如 `CountDownLatch`、`CyclicBarrier` 和 `Semaphore`,每种锁都针对特定的并发场景设计,以解决多线程环境下的同步问题。`StampedLock` 提供了乐观读锁和悲观写锁的选项,而 `Concu

肖哥弹架构博客 1754

java中锁的区别,以及AQS机制

实现机制:AQS 是 java.util.concurrent.locks 包中的一个抽象类,用于构建锁和同步器。它是 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch 等同步工具的基础。底层实现:AQS 内部维护了一个 双向队列(CLH 队列) 和一个 状态变量(state)。状态变量用于表示锁的状态(如锁的持有次数)。当一个线程尝试获取锁时:如果锁未被占用,线程会成功获取锁,并更新状态变量。

weixin_45762066的博客 1208

深入理解Java锁原理(一):偏向锁的设计原理与性能优化

偏向锁的设计基于"锁使用的二八定律":在实际应用中,大部分锁在其生命周期内仅被同一个线程获取,不存在多线程竞争。传统的无锁状态虽然简单,但每次获取锁仍需执行CAS(Compare-and-Swap)操作,而CAS操作虽然轻量,但相比简单的内存比较仍有显著开销。

llwszx的博客 1320

Java 公平锁与非公平锁详解

对比维度公平锁非公平锁排队机制严格遵守FIFO允许插队吞吐量较低较高响应时间可预测不确定实现难度较复杂较简单避免饥饿能不能核心结论公平锁保障绝对的请求顺序非公平锁提供更高的吞吐量Java中锁的默认行为是非公平的(符合大多数场景)在需要严格顺序的业务中才使用公平锁。

yuren_xia的博客 999
上一篇: iOS手势处理零星整理
下一篇: iOS延时执行 - performSelector
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值