什么是锁?
针对数据库来说,锁是数据库系统系统区别于文件系统的一个关键特性。该机制用于管理对共享资源的并发访问!
悲观锁、乐观锁使用场景是针对数据库操作来说的,是一种锁机制。
悲观锁(Pessimistic Lock): 顾名思义,每次去拿数据的时候都悲观地认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock): 顾名思义,每次去拿数据的时候都乐观地认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,即对数据做版本控制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
什么是ABA问题?
- 在多线程运行中,因指令重排序优化的存在,数据依赖性问题。在极短的时间里A线程处理完数据之后又将数据修改回第一次修改时的值。在此过程中尽管B线程从主存拿到了修改前的值,在A处理过程中对B透明,A处理完之后,B线程去操作该数据,并未发现这个变量被修改过。这一过程我们称为:ABA问题。CAS所致!
ABA问题的处理(带时间戳的原子引用 )
* 原子引用(AtomicSatmpedReference):带时间戳的原子引用。
> import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
* Author: Be_insighted
* Description:
*
* @date 2019/12/27 8:52
**/
public class ABADemo {
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);
public static void main(String[] args) {
System.out.println("====================ABA问题产生===================");
new Thread(() -> {
atomicReference.compareAndSet(100, 101);
System.out.println("第一次修改完后:" + atomicReference.get());
atomicReference.compareAndSet(101, 100);
System.out.println("第二次修改完后:" + atomicReference.get());
}, "t1线程").start();
// 保证t1线程完成一次ABA操作
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicReference.compareAndSet(100, 2019) + "当前值:" + atomicReference.get());
}, "t2线程").start();
System.out.println("====================ABA问题解决===================");
new Thread(() -> {
int stam = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName() + "第一次版本号: " + stam);
try {
// 暂停两秒保证t1、t2线程完成操作
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println("第2次版本号:"+atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println("第3次版本号:"+atomicStampedReference.getStamp());
}, "t3线程").start();
// 保证t3线程完成一次ABA操作
new Thread(() -> {
int stam = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName() + "第一次版本号: " + stam);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean b = atomicStampedReference.compareAndSet(100, 2019, stam, atomicStampedReference.getStamp() + 1);
System.out.println("是否修改成功: "+b+";当前版本号: "+atomicStampedReference.getStamp());
System.out.println("当前变量实际值:" + atomicStampedReference.getReference());
}, "t4线程").start();
}
}
说明:为保证线程同时获取主存中的变量,线程休眠
- 我们看下运行结果
====================ABA问题产生===================
第一次修改完后:101
第二次修改完后:100
====================ABA问题解决===================
====================ABA问题产生===================
第一次修改完后:101
第二次修改完后:100
====================ABA问题解决===================
t3线程第一次版本号: 1
t4线程第一次版本号: 1
true当前值:2019
第2次版本号:2
第3次版本号:3
是否修改成功: false;当前版本号: 3
当前变量实际值:100
csdn markdown 快捷键