线程锁

3 阅读2分钟

一: 互斥锁

互斥锁是一种用于控制多喝线程访问共享资源的同步机制,确保在任何时刻只有一个线程可以访问被保护的代码区域(临界区)

核心特性

  1. 互斥性:核心功能,同一时间只允许一个线程持有锁
  2. 临界区保护:持有锁的线程可以安全的执行共享数据的读写操作,不会被其他线程干扰
  3. 原子性保护:锁定和解锁操作本身是原子的,确保锁状态的管理是线程安全的

基本操作

  • 加锁:线程在进入临界区前尝试获取锁。如果锁已被其他线程持有,则当前线程会被阻塞(等待),止到锁被释放
  • 解锁:线程在离开临界区后释放锁,允许其他等待的线程获取它。

类比理解

想象一个公共厕所的单间隔间

  • 隔间=临界区/共享资源
  • 门锁=互斥锁
  • 有人/无人“标识”=锁的状态
  • 一个人进去后锁上门(加锁),使用厕所(访问共享资源),出来后开锁(解锁
  • 其他人必须等里面的人出来后才能进入(互斥访问

实现方式

  1. synchronized关键字(Java内置,最简单)
//锁定当前对象实例
public aynchronized void add(){
    count++
}
//或
public void add(){
    synchronized(lockObject){
        count++
    }
}

  1. java.util.concurrnet.locks.lock接口(如ReentrantLock,更灵活)

关键注意事项

  • 死锁:当多个线程互相持有对方所需的锁并无限等待时发生。例如

    • 线程A持有锁X,请求锁Y
    • 线程B持有锁Y,请求锁X
  • 性能开销:加锁/解锁操作和线程上下文切换会带来开销,过度使用会降低并发性能。

  • 锁粒度

    • 粗粒度锁:锁住大段代码或整个对象,简单并发性差
    • 细粒度锁:锁住最小必要的数据单元,提高并发性但实现复杂

典型应用场景

  • 银行账户余额的扣款/存款操作
  • 多线程下对共享列表/映射的修改
  • 单例模式的懒汉式双重检查锁定
  • 任何需要保证操作原子性的共享资源访问