分布式锁
并发编程中的锁并发编程的锁机制:synchronized和lock。在单进程的系统中,当存
在多个线程可以同时改变某个变量时,就需要对变量或代码块做同步,使其在修改这种变量时能够
线性执行消除并发修改变量。而同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个
代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记
不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记
后再去尝试设置标记。
分布式环境下,数据一致性问题一直是一个比较重要的话题,而又不同于单进程的情况。
分布式与单机情况下最大的不同在于其不是多线程而是多进程。多线程由于可以共享堆内存,
因此可以简单的采取内存作为标记存储位置。而进程之间甚至可能都不在同一台物理机上,
因此需要将标记存储在一个所有进程都能看到的地方。
常见的是秒杀场景,订单服务部署了多个实例,如
秒杀商品有4个,第一个用户购买3个,第二个用户购买2个,理想状态下第一个用户能购买成功,第二
个用户提示购买失败,反之亦然。而实际可能出现的情况是,两个用户都得到库存为4,第一个用户
买到了3个,更新库存之前,第二个用户下了2个商品的订单,更新库存为2,导致出错。
在上面的场景中,商品的库存是共享变量,面对高并发情形,需要保证对资源的访问互斥。在单机环境中,
java中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了。也就是
说单纯的java API 并不能提供分布式锁的能力。分布式系统中,由于分布式系统的分布性,即
多线程和多进程并且分布在不同机器中,synchronized和lock这两种锁将失去原有锁的效果,
需要我们自已实现分布式锁。
常见的分布式锁如下:
基于数据库实现分布式锁:有性能问题
基于缓存实现分布式锁,如redis
基于zookeeper实现分布式锁
使用setnx实现分布式锁
setnx key value
setnx是将key的值设为value,当且仅当key不存在。若给定的key已经存在,则setnx不做任何动作。
返回1,说明该进程获得锁,setnx将键(lock.id)的值设置为锁的超时时间,当前时间+加上锁的有效时间。
返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试setnx操作,以获得锁。
存在死锁的问题
在线程释放锁,即执行del lock.id操作前,需要先判断锁是否已超时。如果锁已超时,那么锁可能已由其他线程
获得,这时直接执行del lock.id操作会导致把其他线程已获得的锁释放掉。
获取分布式锁
public boolean lock(long timeout,TimeUnit timeUnit) throws InterruptedException{
timeout = timeUnit.toMillis(timeout);
long time = timeout + System.currentTimeMillis();
lock.tryLock(timeout, timeUnit);
try{
while(true){
boolean hasLock = tryLock();
if(hasLock){
return true; //获得锁
}else if(timeout < System.currentTimeMillis()){
break;
}
Thread.sleep(1000);
}
}finally{
if(lock.isHeldByCurrentThread()){
lock.unlock();
}
}
return false;
}
public boolean tryLock(){
long time = System.currentTimeMillis();
long timeout = 2000;
String expires = String.valueOf(timeout+time);
if(redisService.setnx("lock.id", expires)>0){
//获取锁,设置超时时间
setLockStatus(expires);
return true;
}else{
String locktime = redisService.get("lock.id");
//检查锁是否超时
if(locktime != null && Long.parseLong(locktime)<time){
String oldlocktime = redis.getset("lock.id",expires);
//旧值与当前时间比较
if(oldlocktime !=null && locktime.equals(oldlocktime)){
//获取锁,设置超时时间
setLockStatus(expires);
return true;
}
}
return false;
}
}
释放锁
public boolean unlock(){
if(lockHolder == Thread.currentThread()){
//判断锁是否超时,没有超时才将互斥量删除
if(lockExpiresTime > System.currentTimeMillis()){
redisService.del("lock.id");
}
lockHolder = null;
return true;
}else{
throws new IllegalMonitorStateException("无法执行解锁操作");
}
}
android入门实例:https://gitbook.cn/gitchat/activity/5d382e64b669c0566c335b32
分享到:
相关推荐
踩到一个关于分布式锁的非比寻常的BUG!.doc
现在很多项目单机版已经不满足了,分布式变得越受欢迎,同时也带来很多问题,分布式锁也变得没那么容易实现,分享一个redis分布式锁工具类,里面的加锁采用lua脚本(脚本比较简单,采用java代码实现,无须外部调用...
分布式锁处理步骤 第一步:查询是否有分布式锁:
redis实现分布式锁,自旋式加锁,lua原子性解锁
主要介绍了Java基于redis实现分布式锁代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
SpringBoot基于redis的分布式锁,有word使用文档,根据文档配置即可使用
Redis+RedisTemplate分布式锁
redis实现分布式锁(java/jedis),其中包含工具方法以及使用demo 本资源是利用java的jedis实现 redis实现分布式锁(java/jedis),其中包含工具方法以及使用demo 本资源是利用java的jedis实现
003 redis分布式锁 jedis分布式锁 Redisson分布式锁 分段锁
本资源为一步一步实现redis分布式锁的demo,利用redis实现高可用的分布式锁,规避各种坑、坑、坑!
自己整理的如何利用redis实现分布式锁,redis实现分布式锁看这一篇绝对够。
zookeeper通过使用curator实现分布式锁来保证数据的一致性。 zookeeper通过使用curator实现分布式锁来保证数据的一致性。
分布式锁
基于zookeeper的分布式锁简单实现,包含测试代码,实用工具类
介绍分布式锁的机制以及业务场景,系统介绍了分布式基础的特性,比较系统介绍了锁和事务的区别,对开源的分布式锁如redis实现分布式锁的机制方案进行阐述
zookeeper做分布式锁
基于Redis方式实现分布式锁
让你对分布式锁理解透彻,基于数据库实现、基于Redis实现、基于ZooKeeper实现,三种分布式锁实现方案详解!
分布式锁的相关介绍,整理了常用的说明和相关使用,参考常见的分布式锁的使用
redisson实现分布式锁,基于aop注解形式使用。