并发编程--乐观锁与悲观锁

1. 什么是乐观锁、悲观锁

乐观锁:总是认为会是最好的情况,每次去取数据都认为别人不会修改,所以不会上锁,但是去更新的时候会判断在这期间有没有人对这个值进行修改,一般使用version机制CAS算法来实现;乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

悲观锁:总是认为会是最坏的情况,每次去取数据都认为别人会修改,所以每次取数据的时候都会上锁,别人取数据就会阻塞,直到它将这个锁释放掉,拿到锁才能取到数据;一般多写的场景下用悲观锁就比较合适,传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronizedReentrantLock等独占锁就是悲观锁思想的实现。

2. 乐观锁的两种实现方式

2.1 version版本号机制

一般是在数据库表中加上一个版本号的字段version,该字段表示数据被修改的次数,数据每次进行修改时,都会进行version+1,当某个线程要更新数据时,会在读取数据的同时也读取到version值,然后提交更新时,会将获取到的version值与此时数据库中的值进行比较,如果相等进行更新,否则重试更新操作,直到更新成功

2.2 CAS无锁算法

即compare and swap(比较和交换),该算法主要涉及三个操作数:

需要读写的内存值 V

进行比较的值           A

拟写入的新值      B

只有当V=A时,通过原子的方式用B值更新V的值,否则不会进行任何操作。一般情况下是一个自旋操作,即不断的重试。

3. 乐观锁的缺点

1)ABA问题:如果线程1获取到变量的值为A,然后在线程1执行更新操作之前的这段时间里,线程2将这个变量的值先改成了B,然后又改回了A,此时线程1再去进行比较,会发现值是相等的,所以会认为在这期间该值没有被修改过.

2)循环时间开销大:前面说过如果失败会一直重试更新操作,知道成功为止,如果一直不成功,会给CPU带来非常大的执行开销

猜你喜欢

转载自www.cnblogs.com/Cryptonym/p/10675529.html