乐观锁和悲观锁
乐观锁:乐观地认为数据一般不会产生并发冲突,所以再在正式提交更新的时候才会对是否发生冲突进行检测,如果发生冲突,则让返回用户错误的信息,让用户决定如何去做
悲观锁:悲观地认为每次拿数据的时候都会被别人修改,所以每次拿数据的时候都会上锁,别人想要拿到这个这个数据就必须等到锁释放。
乐观锁只能适用于冲突较少的场景
悲观锁由于需要竞争锁,所以性能不高
读写锁
多线程之间,如果只是涉及到读操作的话不会引起线程安全的问题,但数据的写入和读之间都需要进行互斥。如果都加锁,会产生极大的性能损耗。
读写锁提供了三个操作:读加锁、写加锁、解锁
能够进一步降低冲突的概率:
读加锁和读加锁之间,不需要互斥
写加锁和写加锁之间,需要互斥
读加锁和写加锁之间,互斥
自旋锁
当一个线程在强锁之后会进入阻塞状态,需要再次被调度才能执行,但是大部分情况下,虽然抢锁失败,不久之后,所就会被释放,所以我们可以让该线程只要没抢到锁,就进行等待
缺点:
如果要抢占的锁没有很快释放,线程不进入阻塞,那么这个线程就是一直在消耗cpu的资源,做无用功。
可重入锁
即允许一个线程多次重复获取同一把锁
比如一个递归函数的内部有加锁操作,那么这个锁就是可重入锁
synchronized关键字锁是一种可重入锁,它的内部是实现了一种“锁计数器”,当synchronized执行多次加锁时,使用计数器自增
解锁时,计数器自减,为0时,才正真解锁
CAS机制
CAS(Compare and swap)“比较并交换”
我们假设要修改内存中的原始数据V,旧的预期值位O,修改后的值位N,那么一个CAS大致有以下操作:
①比较 V 与 A 是否相等
②如果相等,将V的数据替换为N
③返回这次操作是否成功
当多个线程对同一个 数据进行修改的时候,只会有一个线程修改成功,其他的线程由于V与A不同都会返回失败,CAS其实是一个乐观锁
ABA问题
ABA问题其实就是一个值从A变成了B,然后又从B变成了A,我们不清楚从开始的A到最后的A之间发生了什么。
所以我们在修改数据时,加入时间戳作为版本信息,在进行修改时,判断时间能否对的上,保证不会出现老的值。