1、乐观锁与悲观锁的概念
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样其他线程想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。
乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现。
总结:
乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
悲观锁适合多写少读的场景。
2、场景设计
- 创建两个线程,创建方式可自选;
- 定义一个全局共享的 static int 变量 count,初始值为 0;
- 两个线程同时操作 count,每次操作 count 加 1;
- 每个线程做 100 次 count 的增加操作。
结果预期:最终 count 的值应该为 200。
2.1 synchronized 实现
package jvm.juc;
public class CASTest {
static int count = 0;
public static void main(String[] args) throws InterruptedException {
for (int j = 0; j < 2; j++) {
Thread thread = new Thread(() ->{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (CASTest.class) {
for (int i = 0; i < 100; i++) {
count++;
}
}
});
thread.start();
}
Thread.sleep(2000);
System.out.println(count);
}
}
2.2 CAS 实现
package jvm.juc;
import java.util.concurrent.atomic.AtomicInteger;
public class CASTest {
static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 2; i++) {
new Thread(()->{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int j = 0; j < 100; j++) {
count.getAndAdd(1);
}
}).start();
}
Thread.sleep(2000);
System.out.println(count.get());
}
}