Java锁---一图秒懂
2024-06-27 14:05:06 0 举报
AI智能生成
登录查看完整内容
该图片简要概括了Java中的锁机制。在Java中,锁主要用于控制对共享资源的并发访问,从而确保数据的完整性和一致性。根据锁的实现方式和适用场景,可以分为内部锁(如synchronized关键字)和显式锁(如ReentrantLock类)。内部锁是Java内置的锁机制,可以在方法或代码块上使用synchronized关键字实现。显式锁则是Java并发包中提供的锁API,如ReentrantLock、ReentrantReadWriteLock等,它们提供了更加强大的功能和灵活性。在使用锁时,需要注意死锁和饥饿问题,并通过合适的锁机制和策略来避免这些问题。
作者其他创作
大纲/内容
定义:竞争锁时先判断同步队列里是否有其他线程在等待,若有则要到队尾进行排队
ReentrantLock
ReentrantReadWriteLock
公平锁代表
公平锁
定义:竞争锁时先尝试获取锁,失败后才会插入同步队列尾部
synchronized
非公平锁代表
非公平锁
公平与否
定义:锁同时只能被一个线程占有(也叫互斥锁)
ReentrantReadWriteLock中的writeLock
独占锁代表
独占锁
定义:锁可以被多个线程共享
ReentrantReadWriteLock中的readLock
共享锁代表
共享锁
独占与否
定义:线程操作临界区数据前不会上锁,只有真正修改数据时才会比对数据是否已经被其他线程修改过;乐观是中思想,技术基础是:CAS
自适应自旋锁
无限次自旋锁
自旋锁
乐观锁代表
乐观锁
定义:线程操作临界区数据前总是悲观地认为会有别的线程操作改数据,因此每次都先去获取锁,成功后再操作数据
悲观锁代表
悲观锁
悲观与乐观
定义:线程获取了A锁,在没有释放A锁之前,还能继续获取A锁,那么说明A锁是可重入的
可重入锁代表
可重入锁
未实现非可重入锁
非可重入锁
重入与否
定义:线程获取锁失败后会阻塞自身
阻塞锁代表
阻塞锁
定义:无需阻塞
自旋锁代表
阻塞与否
定义:锁与对象实例关联
对象锁代表
对象锁
定义:锁与类对象(class)关联
类锁代表
类锁
按照作用对象区分只有synchronized才会有类锁、对象锁概念
定义:线程在获取锁的过程中可响应中断(抛出中断异常),推出
可中断锁代表
可中断锁
定义:线程在获取锁的过程中不响应中断
不可中断锁代表
不可中断锁
可中断与否
定义:一定时间后,若还是不能获取锁,退出获取锁流程
可限时等待锁代表
可限时等待锁
定义:线程获取锁失败,阻塞直到获取锁为止(除非响应中断)
非限时等待锁代表
非限时等待锁
能否限时等待
锁的分类
关联每个对象
作用域:方法与代码块
类对象
实例对象
作用对象:类与对象
定义:没有线程关联锁
无锁
定义:线程锁住的是MarkWord锁只被一个线程访问,对象头里(MarkWord字段)记录着当前线程ID。当该线程再次获取锁时,仅仅只需要比对MarkWord里的线程ID是否是自己的,若是直接获取锁,否则可能会升级为轻量级锁
适用场景:锁只被一个线程访问的场景
偏向锁
定义:线程锁住的是MarkWord线程访问该锁时,在无锁状态,仅仅只需要一次CAS修改MarkWord里面的指针指向线程自身LockRecord,成功则获取锁,否则可能会升级为重量级锁
适用场景:锁被多个线程交替访问的场景
轻量级锁
定义:线程锁住的是ObjectMonitor对象线程修改ObjectMonitor对象成功,则获取了锁,失败则阻塞等待
适用场景:多个线程并发访问
重量级锁
不同阶段状态锁
维护同步队列
与等待/通知机制有关
维护等待队列
实现的功能
JVM实现
升级版:AbstractQueueLongSynchronizer
定义:全称AbstractQueueSynchronizer,是JUC下的同步器基础框架
基本概念
共享/独占模式
可中断/不可中断
可限时等待/非限时等待
实现基本功能
继承自AQS基本功能
独占模式
公平/非公平
可重入
实现功能
CyclicBarrier
基于此封装的同步器
读锁是共享模式
写锁是独占模式
写写互斥
读读共享
特殊情况:允许同一线程先写,在释放写锁之前,同一线程再读(写锁降级)
读写互斥
读写锁关系
基于AQS的锁
基于AQS共享模式
Semaphore
CountDownLatch
基于AQS独占模式
ThreadPoolExecutor.Worker
基于AQS的同步器
AQS
JUC实现
锁的实现方式
共享的锁变量
保证可见性、顺序性
volatile
同一时刻,只能有一个线程成功修改变量
底层CPU原子性修改变量值
CAS
获取锁失败后加入同步队列
同步队列
因某个条件不满足进入等待队列等待
等待队列
同步/等待队列
基本数据结构
另一个线程调用Object.notify/Object.notifyAll或者Condition.signal/Condition.signalAll后,将等待队列里对应的节点移动到同步队列
两者关系
修改锁变量
获取锁
释放锁
操作数据结构
Parker
UnSafe
AQS使用LockSupport
ParkEvent
线程挂起与唤醒
锁的核心
底层调用NPTL,最终futex
调用Object.wait
线程因某个条件阻塞等待
调用Object.notify/notifyAll
线程被其他线程唤醒
配合synchronized
Condition.await
调用AQS
Condition.signal/signalAll
线程被 其他线程唤醒
通过配合ReentrantLock/ReentrantReadWriteLock使用Condition
同一个锁能关联多个条件/等待
配合AQS
线程被加入到等待队列尾部
线程释放当前持有的锁
线程挂起
从同步队列里移除
成功
继续挂起
失败
被唤醒后继续竞争锁
等待
当其他线程释放锁后,会唤醒同步队列里的线程
线程被从等待队列移动到同步队列里
通知
内部逻辑
配合等待/通知机制
Java锁
![Java锁---一图秒懂](https://www.processon.com/chart_image/template/thumb/667d01125f927303a16b150c.png?tid=667cd8dfedfa9402e9e9e32f)
收藏
0 条评论
回复 删除
下一页