1. 公平锁与非公平锁
按照线程访问顺序获取对象锁。 synchronized 是非公平锁, Lock 默认是非公平锁,可以设置为公平 锁,公平锁会影响性能。
publicReentrantLock() { sync=newNonfairSync(); } publicReentrantLock(booleanfair) { sync=fair?newFairSync() : newNonfairSync(); }
2. 共享式与独占式锁
共享式与独占式的最主要区别在于:同一时刻独占式只能有一个线程获取同步状态,而共享式在同一时 刻可以有多个线程获取同步状态。例如读操作可以有多个线程同时进行,而写操作同一时刻只能有一个 线程进行写操作,其他操作都会被阻塞。
3. 悲观锁与乐观锁
悲观锁,每次访问资源都会加锁,执行完同步代码释放锁, synchronized 和 ReentrantLock 属于悲观锁。 .乐观锁,不会锁定资源,所有的线程都能访问并修改同一个资源,如果没有冲突就修改成功并退出,否 则就会继续循环尝试。乐观锁最常见的实现就是 CAS 。
适用场景: 悲观锁适合写操作多的场景。 乐观锁适合读操作多的场景,不加锁可以提升读操作的性能。
4. 乐观锁有什么问题?
- 乐观锁避免了悲观锁独占对象的问题,提高了并发性能,但它也有缺点:
- 乐观锁只能保证一个共享变量的原子操作。
- 长时间自旋可能导致开销大。假如CAS长时间不成功而一直自旋,会给CPU带来很大的开销。
- ABA问题。CAS的原理是通过比对内存值与预期值是否一样而判断内存值是否被改过,但是会有以 下问题:假如内存值原来是A, 后来被一条线程改为B,最后又被改成了A,则CAS认为此内存值并 没有发生改变。可以引入版本号解决这个问题,每次变量更新都把版本号加一。