Java 中锁分为两类:

  1. 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 JVM 层面实现,使用的时候看不见。
  2. 第二类是在 JDK5 后添加的 Lock 接口以及对应的各种实现类,这属于显式的锁,这就是我们能在代码层面看到锁这个对象,而这些对象的方法实现,大都是直接依赖 CPU 指令,与 JVM 无关。

Synchronized

使用

  • 如果修饰的是具体对象:锁的是对象
  • 如果修饰的是成员方法:锁的是this
  • 如果修饰的是静态方法:锁的是对象.class

synchronized 修饰方法

public class Tuse {
    public static int i;
    public synchronized static void syncTask() {
        i ++;
    }
}

synchronized 代码块

public class Tues {
    public int i;
    public void syncTask() {
        synchronized (this) {
            i ++;
        }
    }
}

类型

  • 偏向锁:这个锁会偏向于第一个获得它的线程,当这个线程再次请求锁的时候不需要进行任何同步操作。
  • 自旋锁:自旋锁是一个过度锁,是从轻量级到重量级锁的过渡。也就是 CAS
  • 轻量级锁:当偏向锁的条件不满足,或有多个线程并发争抢同一锁对象时,优先使用轻量级锁
  • 重量级锁:重量级锁具有完整 Monitor 功能的锁

Lock

Lock 是一个接口,实现类常见的有:

  • 重入锁(ReentrantLock
  • 读锁(ReadLock
  • 写锁(WriteLock
    实现基本都是通过聚合了一个同步器(AbstractQueuedSynchronizer 缩写为 AQS)的子类来完成线程访问控制的。

AbstractQueuedSynchronizer

队列同步器,是用来构建锁或者其他同步组件的基础框架,它使用了一个 int 成员变量表示同步状态,通过内置的 FIFO 队列来完成资源获取线程的排队工作。
同步器的主要使用方法是继承,子类通过同步器并实现它的抽象方法来管理同步状态,在抽象方法的实现过程中免不了对同步状态的更改,这时需要使用同步器提供的 3 个方法来进行操作。三个方法分别是:

  • protected final int getState() 获取当前同步状态。
  • protected final void setState(int newState) 设置当前同步状态。
  • protected final bool compareAndSetState() 使用 CAS 设置当前状态。

重入锁 ReentrantLock

  • 支持一个线程对资源重复加锁。
  • 支持获取锁时的公平和非公平性选择。

读写锁 ReentrantReadWriteLock