一: 互斥锁
互斥锁是一种用于控制多喝线程访问共享资源的同步机制,确保在任何时刻只有一个线程可以访问被保护的代码区域(临界区)
核心特性
- 互斥性:核心功能,同一时间只允许一个线程持有锁
- 临界区保护:持有锁的线程可以安全的执行共享数据的读写操作,不会被其他线程干扰
- 原子性保护:锁定和解锁操作本身是原子的,确保锁状态的管理是线程安全的
基本操作
- 加锁:线程在进入临界区前尝试获取锁。如果锁已被其他线程持有,则当前线程会被阻塞(等待),止到锁被释放
- 解锁:线程在离开临界区后释放锁,允许其他等待的线程获取它。
类比理解
想象一个公共厕所的单间隔间
- 隔间=临界区/共享资源
- 门锁=互斥锁
- 有人/无人“标识”=锁的状态
- 一个人进去后锁上门(加锁),使用厕所(访问共享资源),出来后开锁(解锁)
- 其他人必须等里面的人出来后才能进入(互斥访问)
实现方式
- synchronized关键字(Java内置,最简单)
//锁定当前对象实例
public aynchronized void add(){
count++
}
//或
public void add(){
synchronized(lockObject){
count++
}
}
- java.util.concurrnet.locks.lock接口(如ReentrantLock,更灵活)
关键注意事项
-
死锁:当多个线程互相持有对方所需的锁并无限等待时发生。例如
- 线程A持有锁X,请求锁Y
- 线程B持有锁Y,请求锁X
-
性能开销:加锁/解锁操作和线程上下文切换会带来开销,过度使用会降低并发性能。
-
锁粒度:
- 粗粒度锁:锁住大段代码或整个对象,简单并发性差
- 细粒度锁:锁住最小必要的数据单元,提高并发性但实现复杂
典型应用场景
- 银行账户余额的扣款/存款操作
- 多线程下对共享列表/映射的修改
- 单例模式的懒汉式双重检查锁定
- 任何需要保证操作原子性的共享资源访问