1. 悲观锁和乐观锁:
悲观锁:
假设多个线程会发生竞争,因此在访问共享资源之前,先获取锁。ReentrantLock 是一个悲观锁的例子。
乐观锁:
假设多个线程不会发生竞争,直接进行操作,但在更新时检查是否有其他线程的干扰。CAS (Compare and Swap) 操作是一种乐观锁的实现方式。
2. 共享锁和排他锁:
共享锁:
多个线程可以同时获取共享锁,用于读取共享资源。例如,ReadWriteLock 接口中的读锁是共享锁的例子。
排他锁:
只有一个线程可以获取排他锁,用于更新共享资源。例如,ReentrantLock 接口中的写锁是排他锁的例子。
3. 可重入锁:
可重入锁(Reentrant Lock):
允许同一线程多次获得同一个锁。如果一个线程已经获得了某个锁,那么它可以继续多次获得这个锁而不被阻塞。Java中的 ReentrantLock 和 synchronized 关键字都是可重入锁。
4. 公平锁和非公平锁:
公平锁:
等待时间最长的线程优先获取锁,确保锁的获取是按照请求的顺序进行的。ReentrantLock 可以设置为公平锁。
非公平锁:
锁的获取是无序的,允许新的线程在等待队列中插队,有可能导致某些线程长期无法获取锁。ReentrantLock 默认是非公平锁。
5. 自旋锁:
自旋锁:
线程在获取锁时不立即阻塞,而是通过循环重试(自旋)来获取锁。自旋锁的优势在于避免了线程切换的开销,但如果锁竞争激烈,会导致CPU资源浪费。Java中的 Atomic 类使用了自旋锁。
6. 死锁和活锁:
死锁:
多个线程相互等待对方释放锁,导致所有线程无法继续执行。死锁通常是由于不恰当地使用多个锁或者锁的顺序不当引起的。
活锁:
多个线程在避免死锁的过程中,通过主动释放锁来避免死锁,但是由于竞争过于激烈,导致线程不断地抢夺锁,最终导致无法正常执行。
7. 分段锁:
分段锁:
将共享资源划分为多个段,每个段独立加锁,不同的线程可以同时访问不同的段。分段锁常用于对大规模数据结构的并发访问,如 ConcurrentHashMap。