分布式-基于redis的分布式锁的实现

前言

目前项目很多都是运用了分布式的RPC架构,这其中有一些例如抢票系统、秒杀系统,如果运用传统的单机的安全锁等就很难保证线程安全问题了。所有这里就引入了分布式锁的概念。

本地锁

本地锁就是传统意义上的单机版的线程安全,我主要从我们经常用到的Lock和Sync进行讲解。

Lock和synchronized

这两者都是我们在平时的日常代码编写中经常运用到的,不过他们两者之间还是有区别的

1:lock是一个接口,而sync上java的关键字,sync上内置的语言实现的;

2:sync在发生异常的时候,会自动释放线程占有的锁,因此不会导致死锁的现象发生;而lock在发生异常时,如果没有主动的unLock()去释放锁,就很肯能造成死锁的现象,因此使用lock的时候,需要在finaly快中释放锁。

3:lock可以让等待锁的线程响应中断,而sync不行,在使用sync时,等待的线程会一直等待下去,不能响应中断。

4:lock可以提高多个线程进行读操作的效率

所以在性能上来讲,如果竞争资源不激烈,两者的性能锁差不多的,而当竞争资源非常资源时(即有大量线程同事竞争),此时lock的性能就远远优于sync。(ps:次处有异议,具体如下)

nginx

由于作者是阅读了《java编发变成实战》,所以得出了上述结论4,但是在实战中,并不能一位的觉得lock的性能优于sync,需要具体业务条件具体分析。同时书中也说了下面这段话,往大家自行选择。

nginx

数据库锁

基于数据库的乐观锁

概念

乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。

实现方式

从前做过一个老项目,就是基于乐观锁。我们在一个表中加入了一个version(版本号)字段。

当我们要从数据库中读数据的时候,同时把这个version字段也读出来,如果要对读出来的数据进行更新后写回数据库,则需要将version加1,同时将新的数据与新的version更新到数据表中,且必须在更新的时候同时检查目前数据库里version值是否比之前的版本号大,如果是,则正常更新。如果不是,则更新失败,说明在这个过程中有其它的进程去更新过数据了。


总体来说乐观锁必须满足两个条件

1:必须要有一个版本号(version)的概念。

2:更新数据的时候都必须先判断版本号,然后再写新数据。

基于数据库的悲观锁

概念

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。

实现方式

zookeeper锁

redis分布式锁

总结

未完待续

-------------本文结束感谢您的阅读-------------