java锁的底层原理

本文详细探讨了Java中的锁机制,包括synchronized的四种应用方式、内置锁的实现、锁优化策略(如锁升级、锁粗化、锁消除等)、CAS操作的优缺点、volatile的内存语义及其与synchronized的区别。同时讲解了ReentrantLock的非公平锁与公平锁的实现原理,以及Condition类如何实现更精确的线程控制。最后,文章提到了死锁的概念、避免与恢复策略,以及锁模式和Happen-Before原则在并发控制中的重要作用。
摘要由CSDN通过智能技术生成

知识整理

  1. Synchronized 内置锁,JVM级别
    1. 使用
    2. 底层 锁升级过程、CAS操作的缺点【替换线程和copy mw】
    3. 优化
      1. 代码优化:同步代码块、减少锁粒度、读锁并发
      2. JDK自带 偏置锁、轻量级锁(CAS操作)、自适应自旋、锁粗化、锁消除
  2. Volatile
      1. 概念:非阻塞可见性、禁止指令重排序*
      2. 与syn区别: 无法实现原子操作、使用场景--单线程、不依赖当前值
  3. Reentrantlock 显示锁:基于AQS实现,API级别
    1. AQS原理:
      1. 数据结构:state、waitstate【signal-1、传播-3】、
      2. 独占、共享 tryAcquireShared
    2. 非公平锁
    3. 特性锁 可重入、轮询、定时、可中断
    4. 优点、使用场景
    5. 与Syn区别、Syn优点
  4. 死锁
    1. 概念:多个线程因竞争资源而互相等待的僵局;4个必要条件:资源互斥、不可剥夺、保持与请求、循环等待
    2. 死锁避免:锁顺序、锁时限、死锁检测与恢复
    3. 死锁检测与恢复:分配资源时不加条件;检测时机:进程等待、定时、利用率下降
      1. 检测算法:资源分配表、遍历锁关系图
      2. 撤销进程、设置线程随机优先级
  5. 锁模式
    1. 读锁、写锁
    2. 乐观锁:用户解决---数据版本id、时间戳;CAS;适合写操作少的场景;MVCC实现
    3. 悲观锁:数据库行锁、页锁...

 

synchronized的4种应用方式 jvm内部实现 称为:内置锁

synchronized关键字最主要有以下3种应用方式,都是作用在对象上

  1. 修饰类,作用范围:synchronized括号内, 作用对象:类的所有对象;synchronized(Service.class){ }
  2. 修改静态方法,作用范围:整个静态方法, 作用对象:类的所有对象;
  3. 修饰方法,被修饰的同步方法,作用范围:整个方法, 作用对象:调用这个方法的对象;
    1. 缺点:A线程执行一个长时间任务,B线程必须等待
  4. 修饰代码块,被修饰的代码块同步语句块,作用范围:大括号内的代码, 作用对象:调用这个代码块的对象;
    1. 优点:减少锁范围,耗时的代码放外面,可以异步调用

 

notify 方法实现只唤醒一个线程,由操作

lock.notify()方法最终通过ObjectMonitor的void notify(TRAPS)实现:

1、如果当前_WaitSet【线程等待的集合】为空,即没有正在等待的线程,则直接返回;

2、通过ObjectMonitor::DequeueWaiter 出队方法,获取_WaitSet列表中的第一个ObjectWaiter节点,实现也很简单【选择哪个线程取决于操作系统对多线程管理的实现】

3、根据不同的策略,将取出来的ObjectWaiter节点,加入到Contention List,或自旋操作,CAS改变第一个节点的的指针为新增节点

 

notifyAll方法实现

lock.notifyAll()方法最终通过ObjectMonitor的void notifyAll(TRAPS)实现:

通过for循环取出_WaitSet的ObjectWaiter节点,并根据不同策略,加入到_EntryList或则进行自旋操作。

从JVM的方法实现中,可以发现:notify和notifyAll并不会释放所占有的ObjectMonitor对象,其实真正释放ObjectMonitor对象的时间点是在执行monitorexit指令,

一旦释放ObjectMonitor对象了,Entryset中ObjectWaiter节点所保存的线程,就可以开始竞争ObjectMonitor对象进行加锁操作了,和ready线程竞争?

 

2.锁的的实现:内存机制 copy到工作内存->   修改->   刷新主存   的过程,才会释放它得到的锁,达到线程安全。

  1. 锁住(lock)
  2. 主->从 read load 将需要的数据从主内存拷贝到自己的工作内存(read and load)
  3. 修改 use assign 根据程序流程读取或者修改相应变量值(use and assign)
  4. 从->主 store write将自己工作内存中修改了值的变量拷贝回主内存(store and write)
  5. 释放对象锁(unlock)

线程安全:

  1. 当多个线程访问某个类,其始终能表现出正确的行为
  2. 采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,限制其他线程访问,直到锁释放

 

Java中的锁优化 代码方式、JDK自带方式

1.代码 锁优化

  1. 减少锁持有时间 
    1. 使用同步代码块,而非同步方法;
  2. 减小锁粒度
    1. JDK1.6中 ConcurrentHashMap采取对segment加锁而不是整个map加锁,提高并发性;
  3. 锁分离  读锁之间不互斥;读写分离
    1. 根据同步操作的性质,把锁划分为的读锁和写锁,读锁之间不互斥,提高了并发性

2.JDK1.6 锁优化 synchronized底层

1.引入偏向锁、轻量级锁

  1. 锁主要存在四中状态,依次是:无锁状态01、偏向锁状态01、轻量级锁状态00、重量级锁状态10,
  2. 会随着竞争的激烈而逐渐升级,锁可以升级不可降级,提高 获得锁和释放锁 效率
  3. “轻量级锁”和“偏向锁”作用:减少 获得锁和释放锁 的性能消耗

优点

缺点

适用场景

偏向锁

记录线程iD,若该线程,则不加锁;锁状态01

如果线程间存在锁竞争,会带来额外的锁撤销的消耗。

适用于只有一个线程访问同步块场景。

轻量级锁

</
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值