【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )

简介: 【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )

文章目录

一、悲观锁示例 ( ReentrantLock )

二、重量级锁弊端

三、锁的四种状态 ( 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 )

四、锁的四种状态之间的转换 ( 无锁状态 -> 偏向锁 -> 轻量级锁 -> 重量级锁 )





一、悲观锁示例 ( ReentrantLock )


ReentrantLock 与 synchronized 都是悲观锁 ;


ReentrantLock 是 Lock 接口的实现类 ,


public class ReentrantLock implements Lock, java.io.Serializable {
}


Lock 是一种锁的机制 , 调用 lock() 方法 , 表示要对下方的代码进行加锁 , 这些代码是线程安全的 ;


代码执行完毕后 , 调用 unlock() 释放锁 ;


在 lock() 与 unlock() 之间的内容 , 就是同步代码块内容 ;


public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}


悲观锁都是重量级锁 ;






二、重量级锁弊端


JDK 1.2 1.21.2 之间 , 只有一个 synchronized 重量级锁 ;


Java 虚拟机创建了线程 A , B 两个线程 , JVM 将线程托管给操作系统进行调度执行 , 线程同步依靠 synchronized 重量级锁实现 , 线程 A , B 之间会进行竞争 , 哪个抢到 synchronized 锁 , 哪个线程就可以执行 ;


使用 synchronized 使用起来效率很低 , 假如在 synchronized 同步代码块中 , 只有一行代码 , 执行 1 11 ms , 但是系统调度线程 , 可能需要 20 2020 ms 才能轮到线程执行 , 线程执行的时间远远小于调度时间 , 这样线程执行效率很低 ;


为了 Java 程序的提升执行效率 , Java 引入了 4 44 种锁状态 , 无锁 , 偏向锁 , 轻量级锁 , 重量级锁 ;






三、锁的四种状态 ( 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 )


Java 虚拟机堆内存中的对象数据中 , 每个对象都有一个对象头 , 结构如下 :

image.png



对象头 中封装了 锁的状态 , 当锁的状态发生改变时 , 对应的锁的标志位也进行相应修改 ;



无锁状态 : 不进行加锁 , 线程不安全 ;


偏向锁 : 第 1 11 个访问 共享资源 的线程 A , 做一个标记 , 不加锁 , 这个标记称为 " 偏向锁 " ; 偏向锁 偏向第一个访问的线程 ; 如果没有新的线程竞争该锁 , 则该 偏向锁一直被该线程持有 , 不会释放锁 ; 如果出现多个线程同时访问 , 持有偏向锁的线程会 释放该偏向锁 , 并添加轻量级锁 ;


锁竞争 : 多个线程尝试获取同一个锁 ;

没有竞争 : 如果每次获取都很顺利 , 没有出现阻塞 , 则没有竞争 ;

有竞争 : 如果线程尝试获取锁 , 但是锁被其它线程持有 , 那么 该线程需要等待 , 期间 阻塞或自旋 , 只要是等待就会产生消耗 , 这就产生了锁竞争 , 并且 有一定的性能消耗 ;

锁竞争消耗 : 多数情况下锁会被多个线程获取多次 , 多个线程竞争一个锁 , 这样就存在竞争 , 竞争期间 阻塞或自旋 , 锁获取的代价很大 ;

偏向锁优点 : 降低了线程获取锁的代价 , 偏向锁不存在锁竞争问题 ;

偏向锁意义 : 偏向锁并 不是真正意义上的锁 , 只是给单线程执行加了层保险 , 如果没有线程竞争该锁 , 则正常执行 , 如果有线程竞争 , 则将偏向锁升级为轻量级锁 ;

轻量级锁 : 自旋锁 , 等待期间一直做自旋操作 , 效率较高 , 但是空耗 CPU 性能 ; 自旋就是 while / for 循环 ;


重量级锁 : 系统提供的 synchronized , ReentrantLock 等重量级锁 , 由操作系统进行调度 , 可进行阻塞 ;






四、锁的四种状态之间的转换 ( 无锁状态 -> 偏向锁 -> 轻量级锁 -> 重量级锁 )


锁的四种状态之间转换 : 在保证线程安全的前提下 , 尽可能提升效率 ;


无锁 : 刚开始执行时 , 无锁 ;


无锁 -> 偏向锁 : 第 1 11 个线程访问共享资源时 , 无锁状态升级为偏向锁 ;


偏向锁 -> 轻量级锁 : 第 2 22 个线程再来访问 共享资源 时 , 偏向锁 升级为 轻量级锁 ;


轻量级锁 -> 重量级锁 : 如果 自旋线程数 超过 CPU 核数一半 , 或 单个线程超过 10 1010 次自旋 , 自动将锁升级为重量级锁 ;


image.png

目录
相关文章
|
10月前
|
存储 架构师 安全
深入理解Java锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁(图解+史上最全)
锁状态bits1bit是否是偏向锁2bit锁标志位无锁状态对象的hashCode001偏向锁线程ID101轻量级锁指向栈中锁记录的指针000重量级锁指向互斥量的指针010尼恩提示,讲完 如减少锁粒度、锁粗化、关闭偏向锁(-XX:-UseBiasedLocking)等优化手段 , 可以得到 120分了。如减少锁粒度、锁粗化、关闭偏向锁(-XX:-UseBiasedLocking)等‌。JVM锁的膨胀、锁的内存结构变化相关的面试题,是非常常见的面试题。也是核心面试题。
深入理解Java锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁(图解+史上最全)
|
Java 开发者
Java 中的锁是什么意思,有哪些分类?
在Java多线程编程中,锁用于控制多个线程对共享资源的访问,确保数据一致性和正确性。本文探讨锁的概念、作用及分类,包括乐观锁与悲观锁、自旋锁与适应性自旋锁、公平锁与非公平锁、可重入锁和读写锁,同时提供使用锁时的注意事项,帮助开发者提高程序性能和稳定性。
569 3
|
3月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
228 1
|
3月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
243 1
|
4月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
199 0
|
4月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
351 16
|
5月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
5月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
6月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
387 83

热门文章

最新文章