Java 中的锁分类
乐观锁/悲观锁
乐观锁: 就是没有加锁的实现. AtomicInteger中的实现就是不加锁的,通过自旋比较实现(CAS)
悲观锁: 就是加锁的实现,认为不加锁是会出问题的 ,ReentrantLock和synchronized都是悲观锁
可重入锁
ReentrantLock和synchronized都是可重入锁
可重入锁又名递归锁, 指的是一个线程在外层方法获得锁时,可以直接进入到内层的加锁的方法中.
自旋锁
指的是对synchronized获得锁的一种描述(特点), 线程在获得锁时,是自旋的不断尝试去获得锁
公平锁/非公平锁
公平锁: 就是排队获得锁,有先来后到 ReentrantLock 既可以是公平锁也可以是非公平锁
非公平锁: 就是抢锁,谁抢到谁执行, 有可能后来的线程先抢到锁 synchronized ReentrantLock
读写锁
ReentrantReadWriteLock
特点: 读读不互斥, 读写互斥, 写写互斥
适合读(查询)多,写少的场景, 提高读的效率
共享锁和独占锁
独占锁: synchronized ReentrantLock都是独占锁,就是有我没他,一次只能有一个线程执行.
共享锁: 一个锁可以被多个线程持有, 读写锁中的读锁就是共享锁
synchronized锁的实现
jdk1.7之后,对synchronized锁进行了优化(jdk7之前synchronized锁没有状态,都是自旋的获取锁),
jdk7之后为synchronized锁设计了不同的状态.
无锁状态: 没有线程进入到同步代码块就是无锁状态
偏向锁状态: 只有一个线程访问同步代码块时,同步锁中记录线程id,下次线程访问时,可以快速的获得锁.
轻量级锁状态: 当线程数量大于1个之后,锁状态由偏向锁升级为轻量级锁, 线程不会阻塞,以自旋方式获得锁,
提高获取锁的效率.
重量级锁状态: 当锁状态为轻量锁时,如果线程自旋到一定次数还获取不到锁,那么锁会升级为重量级锁,让获取不到锁的线程进入到阻塞状态,等待操作系统调度.
使用synchronized锁的时候,必须为锁提供一个同步锁对象的,此对象就是用来记录锁状态的
对象中有一个区域叫对象头,对象头中有一块区域叫mark word,记录对象运行时的一些数据,如锁状态,哈希值,GC分代年龄,当前线程id.
synchronized是java中内置的一种的锁,底层实现是靠底层指令进行控制的,
使用时必须提供一个同步锁对象,用来记录锁的各种状态.
AQS
AbstractQueuedSynchronizer 抽象同步队列, 并发包下面很多类的底层实现都会用到
内部有一个int类的变量state,用来记录有没有线程使用
内部会构建一个队列,用来存储没有获得锁的线程
ReentrantLock锁实现
ReentrantLock 基于 AQS的,
ReentrantLock 可以实现公平锁和非公平锁
内部结构
公平和非公平的区别