悲观锁/乐观锁
悲观锁
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别的线程会修改,所以每
次在拿数据的时候都会上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
适合写操作多的场景,先加锁可以保证写操作时数据正确。显式的锁定之后再操作同步资源
//=============悲观锁的调用方式
public synchronized void m1()
{
//加锁后的业务逻辑......
}
// 保证多个线程使用的是同一个lock对象的前提下
ReentrantLock lock = new ReentrantLock();
public void m2() {
lock.lock();
try {
// 操作同步资源
}finally {
lock.unlock();
}
}
乐观锁
乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别的线程不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间有没有其他线程去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读少写的应用类型,这样可以提高吞吐量,
乐观锁的实现方式:
1、使用版本标识来确定读到的数据版本号与原来的数据版本号是否一致。提交后修改版本标
识,不一致时可以采取丢弃和重试的策略。
2、java 中的 Compare and Swap 即 CAS ,当多个线程尝试使用 CAS 同时更新
同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的
线程并不会被挂起,会再次尝试(自旋)更新操作。
适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。
乐观锁则直接去操作同步资源,是一种无锁算法,得之我幸不得我命,再抢
Java原子类中的递增操作就通过CAS自旋实现的。
//=============乐观锁的调用方式
// 保证多个线程使用的是同一个AtomicInteger
private AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.incrementAndGet();