Skip to content

Java中的锁分为以下几种:

  • 乐观锁、悲观锁
  • 独享锁、共享锁
  • 公平锁、非公平锁
  • 互斥锁、读写锁
  • 可重入锁
  • 分段锁
  • 锁升级(无锁 - > 偏向锁 - > 轻量级锁 - > 重量级锁) jdk1.6

这些锁的分类并不全是指锁的状态,有的指锁的特性,有的指锁的设计。

1、 乐观锁 & 悲观锁 (概念)

乐观锁: 乐观锁认为一个线程去拿数据的时候不会有其他线程对数据进行更改,所以不会上锁

​ 实现方式:CAS 机制、版本号机制

悲观锁: 悲观锁认为一个线程去拿数据时一定会有其他线程对数据进行更改。所以一个线程在拿数据的时候都会加锁,这样别的线程想修改这个数据时就会阻塞。比如synchronized关键字的实现就是悲观锁。

2、独享锁 & 共享锁 (概念)

独享锁: 该锁一次只能被一个线程所持有

共享锁: 该锁可以被多个线程所持有

synchronizedReentrantLockReentranReadWriteLock.WriteLock 是独享锁

ReentranReadWriteLock.ReadLock 是共享锁

独享锁与共享锁通过 AQS(AbstractQueuedSynchronizer)来实现的,通过实现不同的方法,来实现独享或共享

3、互斥锁 & 读写锁 (实现)

互斥锁 的具体实现就是 synchronizedReentrantLockReentrantLockJDK1.5的新特性,采用ReentrantLock可以完全替代替换synchronized传统的锁机制,更加灵活。

读写锁 的具体实现就是 ReadWriteLock

4、可重入锁

对于同一个线程在外层方法获取锁的时候,在进入内层方法时也会自动获取锁

优点:避免死锁

举例:ReentrantLocksynchronized

5、公平锁 & 非公平锁

公平锁: 多个线程相互竞争时要排队,多个线程按照申请锁的顺序来获取。

​ 比如 new ReentranctLock(true)

非公平锁: 多个线程相互竞争时,先尝试插队,插队失败再排队。效率相对高

​ 比如:synchronizednew ReentrantLock()

6、分段锁

分段锁并不是具体的一种锁,而是一种锁的设计。

分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。ConcurrentHashMap底层就用了分段锁,使用Segment,就可以进行并发使用了,而HashMap是非线程安全的就差在了分段锁上。

7、偏向锁 & 轻量级锁 & 重量级锁

JDK 1.6 为了减少获得锁和释放锁所带来的性能消耗,在JDK 1.6里引入4种锁的状态: 无锁、偏向锁、 轻量级锁和重量级锁,它会随着多线程的竞争情况逐渐升级,但不能降级

大多数情况下,锁不仅不存在多线程竞争,而且总是由同一个线程获得,为了不让这个线程每次获得锁都需要CAS操作的性能消耗,就引入了偏向锁。当一个线程访问对象并且获取锁时,会在对象头里存储锁偏向的这个线程的ID,以后该线程再访问该对象时只需判断对象头的Mark Word里是否有这个线程的ID,如果有就不需要进行CAS操作,这就是偏向锁。

当线程竞争更激烈时,偏向锁就会升级为轻量级锁,轻量级锁认为虽然竞争存在,但是理想情况下竞争的程度很低,通过自旋方式等待一会儿上一个线程就会释放锁,但是当自旋超过了一定的次数,或者一个线程持有锁,一个线程在自旋,又来了第三个线程访问时(反正就是竞争又增大了),轻量级锁就会膨胀为重量级锁,重量级锁就是Synchronized,重量级锁会使除了当前拥有锁的线程以外的线程都阻塞。