悲观锁:
认为线程安全问题一定会发生,因此在操作数据之前先获取锁,确保线程串行执行。
例如Synchronized、Lock都属于悲观锁
乐观锁:
认为线程安全问题不一定会发生,因此不加锁,只是在更新数据时去判断有没有其它线程对数据做了修改。
如果没有修改则认为是安全的,自己才更新数据。
如果已经被其它线程修改说明发生了安全问题,此时可以重试或异常。
乐观锁的关键是判断之前查询得到的数据是否有被修改过,常见的方式有两种
版本号法:
每次修改时查看版本号有没有变化
每次对数据进行修改时都要对版本号进行修改
当有请求进来时先查询数据和版本号,但在操作数据时要添加对版本号的判断是否等于查到的版本
如果版本号相等没有被其它线程修改是安全的,便可以更新数据。
如果版本号的值不相等说明在我查到数据和修改数据之间已经被其它线程修改,发生了安全问题,此时可以重试或异常。
如果当线程1和线程2同时查询到数据和版本号为1时,并且都要对数据进行修改,那么线程1进来发现版本号与查到的版本号一致直接修改,此时版本号已经等于2,那么线程2进来修改时查到的版本号等于1数据中的版本号等于2,因此不一致说明发生了线程安全问题,此时可以重试或异常。
![](https://i-blog.csdnimg.cn/blog_migrate/b3ea0db6660a48f06632962d9af31685.png)
CAS法
每次修改时查看数据本身有没有变化
此方法与版本号用法一致,只是不在判断版本号的变化,而是判断数据本身是否发生修改
![](https://i-blog.csdnimg.cn/blog_migrate/e5310b13e786394deecf90b0f714bb4e.png)