抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

思维导图

文章已收录Github精选,欢迎Starhttps://github.com/yehongzhi/learningSummary

悲观锁

悲观锁是平时开发中经常用到的一种锁,比如ReentrantLocksynchronized等就是这种思想的体现,它总是假设别的线程在拿线程的时候都会修改数据,所以每次拿到数据的时候都会上锁,这样别的线程想拿这个数据就会被阻塞。如图所示:

synchronized是悲观锁的一种实现,一般我们都会有这样使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static Object monitor = new Object();

public static void main(String[] args) throws Exception {
//锁一段代码块
synchronized (monitor){

}
}
//锁实例方法,锁对象是this,即该类实例本身
public synchronized void doSome(){

}
//锁静态方法,锁对象是该类,即XXX.class
public synchronized static void add(){

}

我们以最简单的同步代码块来分析,其实就是将synchronized作用于一个给定的实例对象monitor,即当前实例对象就是锁对象,每次当线程进入synchronized包裹的代码块时就会要求当前线程持有monitor实例对象锁,如果当前有其他线程正持有该对象锁,那么新到的线程就必须等待,这样也就保证了每次只有一个线程执行synchronized内包裹的代码块

从上面的分析中可以看出,悲观锁是独占和排他的,只要操作资源都会对资源进行加锁。假设读多写少的情况下,使用悲观锁的效果就不是很好。这时就引出了接下来要讲的乐观锁。

乐观锁

乐观锁,顾名思义它总是假设最好的情况,线程每次去拿数据时都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。如图所示:

一般乐观锁在java中是通过无锁编程实现的,最常见的就是CAS算法,比如Java并发包中的原子类的递增操作就是通过CAS算法实现的。

CAS算法,其实就是Compare And Swap(比较与交换)的意思。目的就是将内存的值更新为需要的值,但是有个条件,内存值必须与期待的原内存值相同。展开来说,我们有三个变量,内存值M,期望的内存值E,更新值U,只有当M==E时,才会将M更新为U

CAS算法实现的乐观锁在很多地方有应用,比如并发包的原子类AtomicInteger类。在自增的时候就使用到CAS算法。