“分布式锁”是用来解决分布式应用中“并发冲突”的一种经常使用手段,实现方式通常有基于zookeeper及基于redis二种。具体到业务场景中,咱们要考虑二种状况:redis
好比:一些不是很重要的场景,好比“监控数据持续上报”,某一篇文章的“已读/未读”标识位更新,对于同一个id,若是并发的请求同时到达,只要有一个请求处理成功,就算成功。并发
用活动图表示以下:分布式
好比:一个订单,客户正在前台修改地址,管理员在后台同时修改备注。地址和备注字段的修改,都必须正确更新,这二个请求同时到达的话,若是不借助db的事务,很容易形成行锁竞争,但用事务的话,db的性能显然比不上redis轻量。ide
解决思路:A,B二个请求,谁先抢到分布式锁(假设A先抢到锁),谁先处理,抢不到的那个(即:B),在一旁不停等待重试,重试期间一旦发现获取锁成功,即表示A已经处理完,把锁释放了。这时B就能够继续处理了。性能
但有二点要注意:线程
a、须要设置等待重试的最长时间,不然若是A处理过程当中有bug,一直卡死,或者未能正确释放锁,B就一直会等待重试,可是又永远拿不到锁。blog
b、等待最长时间,必须小于锁的过时时间。不然,假设锁2秒过时自动释放,可是A还没处理完(即:A的处理时间大于2秒),这时锁会由于redis key过时“提早”误释放,B重试时拿到锁,形成A,B同时处理。(注:可能有同窗会说,不设置锁的过时时间,不就完了么?理论上讲,确实能够这么作,可是若是业务代码有bug,致使处理完后没有unlock,或者根本忘记了unlock,分布式锁就会一直没法释放。因此综合考虑,给分布式锁加一个“保底”的过时时间,让其始终有机会自动释放,更为靠谱)事务
用活动图表示以下:it
用2个线程模拟并发场景,跑起来后,输出以下:class
能够看到T2线程没抢到锁,直接抛出了预期的异常。
把44行的注释打开,即:换成不容许丢数据的模式,再跑一下:
能够看到,T1先抢到锁,而后通过2秒的处理后,锁释放,这时T2重试拿到了锁,继续处理,最终释放。