【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

目录
相关文章
|
16天前
|
并行计算 安全 Java
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
83 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
2月前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
2月前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
2月前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
85 12
|
2月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
221 2
|
3月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
3月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
2月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
2月前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
72 3
|
2月前
|
开发框架 安全 Java
Java 反射机制:动态编程的强大利器
Java反射机制允许程序在运行时检查类、接口、字段和方法的信息,并能操作对象。它提供了一种动态编程的方式,使得代码更加灵活,能够适应未知的或变化的需求,是开发框架和库的重要工具。
87 4

热门文章

最新文章