作一个积极的人html
编码、改bug、提高本身java
我有一个乐园,面向编程,春暖花开!git
=================================================github
对人工智能感兴趣的伙伴,分享一个我朋友的人工智能教程。零基础!通俗易懂!风趣幽默!你们能够看看是否对本身有帮助,点击这里查看教程。redis
=================================================数据库
我在实际环境中遇到了这样一种问题,分布式生成id的问题!由于业务逻辑的问题,我有个生成id的方法,是根据业务标识+id 当作惟一的值! 而uuid是递增生成的,从1开始一直递增,那么在同一台机器上运行代码,加上同步方法(synchronized),这个生成id的方法就是ok!编程
可是由于业务扩展或者说为了安全,项目运行在两台机器上,此时单个的同步方法(synchronized或者Lock)就不能防止id的重复了!!!安全
要解决上面的这个问题,其余有以下解决办法! (1):每台机器生产Id的代码,key+id 能够在前加上机器编号区分,key + id --- >机器惟一编号 + key + id (2):使用数据库行锁(单个数据库的是时候,如何是分布式数据库也会出现问题),在须要插入id的表加上行锁,防止数据重复致使程序异常! (3):使用分布式锁 bash
网上有不少的讲解分布式锁的文章,可是细细分析不少的代码仍是有不少的问题的,以下代码片断摘自博文:服务器
public void lock(long timeout) {
long nano = System.nanoTime();
timeout *= 1000000;
final Random r = new Random();
try {
while ((System.nanoTime() - nano) < timeout) {
if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
locked = true;
logger.debug("add RedisLock[" + key + "].");
break;
}
Thread.sleep(3, r.nextInt(500));
}
} catch (Exception e) {
}
}
复制代码
上面的代码博主也说了:若是长时间获取不到,就会获取锁失败,至关于没加锁!
这里还有可能发生其余问题:
(1)并发状况,expire主动释放锁的时候,可能释放的是别人的锁(不懂请自行查询相关资料)
(2)Redis服务挂掉,锁失败,至关于没加锁!最好使用主从+哨兵提升 高可用
注:使用的时候要注意上面问题!!!
还有一种摘自博文: www.cnblogs.com/0201zcr/p/5… 这个博问分析的:
while (timeout >= 0) {
long expires = System.currentTimeMillis() + expireMsecs + 1;
String expiresStr = String.valueOf(expires); //锁到期时间
if (this.setNX(lockKey, expiresStr)) {
// lock acquired
locked = true;
return true;
}
String currentValueStr = this.get(lockKey); //redis里的时间
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
//判断是否为空,不为空的状况下,若是被其余线程设置了值,则第二个条件判断是过不去的
// lock is expired
String oldValueStr = this.getSet(lockKey, expiresStr);
//获取上一个锁到期时间,并设置如今的锁到期时间,
//只有一个线程才能获取上一个线上的设置时间,由于jedis.getSet是同步的
if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
//防止误删(覆盖,由于key是相同的)了他人的锁——这里达不到效果,这里值会被覆盖,可是由于什么相差了不多的时间,因此能够接受
//[分布式的状况下]:如过这个时候,多个线程刚好都到了这里,可是只有一个线程的设置值和当前值相同,他才有权利获取锁
// lock acquired
locked = true;
return true;
}
}
timeout -= DEFAULT_ACQUIRY_RESOLUTION_MILLIS;
/*
延迟100 毫秒, 这里使用随机时间可能会好一点,能够防止饥饿进程的出现,即,当同时到达多个进程,
只会有一个进程得到锁,其余的都用一样的频率进行尝试,后面有来了一些进行,也以一样的频率申请锁,这将可能致使前面来的锁得不到知足.
使用随机的等待时间能够必定程度上保证公平性
*/
Thread.sleep(DEFAULT_ACQUIRY_RESOLUTION_MILLIS);
}
复制代码
这个相比第一个完善了误删除key的问题,可是要合理的设置超时时间 (要了解具体加锁的业务),不然的话,也会使锁失效。
Redisson的介绍能够到:github.com/redisson/re… 这里去了解!
我这里说一下使用时候要注意的问题:
1:文档里面说明了支持Redis 2.8以上版本,支持Java1.6+以上版本。根据本身的环境选择合适的版本!
2:2.8.1的redisson 须要使用 netty的jar包, 不然报错:Hopper: java.lang.NoClassDefFoundError: io/netty/channel/EventLoopGroup。
3:2.8.1的redisson须要jackson 2.5+版本,不然报错bjectMapper.addMixIn method not fond。
我写了一个简单的例子,本身也作了一下测试,使用的Redis主从+哨兵模式! demo的目录结构,具体的源码我放到github上面,地址:github.com/dufyun/lear…
注:这里必定要先安装Redis服务,若是没有安装Redis服务,请参考这篇:blog.csdn.net/u010648555/… 若是Redis服务安装到服务器上面,请修改代码中的Redis地址和端口!不然运行不起了!
运行这个类UUidGeneratorLockTest就能够看到效果!测试结果我也在readme.txt进行了总结!
若是在测试和学习的过程当中有疑问,能够随时和我联系,也能够加左侧的群或者QQ互相探讨!谢谢!
这个时代,信息爆炸,各类技术博文之间互相参考,真正的问题可能没有暴露出来,真正好的文章仍是须要鉴别的!(我本身也会参考一些文章,可是我都会进行一些本身验证,一个是为准确性,一个加深本身的对知识的认识)
我也要反思,本身以前也写过一些博文,也是遇到问题了,去网上搜一些解决方案,不少方案确实是理论上能够解决当前遇到的问题,当时去深究,就会发现不少的不完整性!
多思考,多测试!让代码可以更加高效、健壮和安全!
Redis实现分布式锁全局锁—Redis客户端Redisson中分布式锁RLock实现
分布式锁的几种实现方式
谢谢你的阅读,若是您以为这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你天天开心愉快!
无论作什么,只要坚持下去就会看到不同!在路上,不卑不亢!
愿你我在人生的路上能都变成最好的本身,可以成为一个独挡一面的人
© 天天都在变得更好的阿飞云