一:前言

我在实际环境中遇到了这样一种问题,分布式生成id的问题!因为业务逻辑的问题,我有个生成id的方法,是根据业务标识+id当做唯一的值!

而uuid是递增生成的,从1开始一直递增,那么在同一台机器上运行代码,加上同步方法(synchronized),这个生成id的方法就是ok!

但是因为业务扩展或者说为了安全,项目运行在两台机器上,此时单个的同步方法(synchronized)就不能防止id的重复了!!!

要解决上面的这个问题,其他有如下解决办法!

(1):每台机器生产Id的代码,key+id 可以在前加上机器编号区分,key + id --- >机器唯一编号 + key + id

(2):使用数据库行锁(单个数据库的是时候),在需要插入id的表加上行锁,防止数据重复导致程序异常!

(3):使用分布式锁

二:分布式锁简介

网上有很多的讲解分布式锁的文章,但是细细分析很多的代码还是有很多的问题的,如下代码片段摘自博文:

https://my.oschina.net/91jason/blog/517996?p=1

http://blog.csdn.net/u010359884/article/details/50310387

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服务挂掉,锁失败,相当于没加锁!

注:使用的时候要注意上面问题!!!

还有一种摘自博文:

http://www.cnblogs.com/0201zcr/p/5942748.html

这个博问分析的:

 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分布式锁的介绍和简单的使用

Redisson的介绍可以到:https://github.com/redisson/redisson/wiki/1.-概述 这里去了解!

我这里说一下使用时候要注意的问题:

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上面,地址:https://github.com/dufyun/kuyu/tree/master/redissondemo

注:这里一定要先安装Redis服务,如果没有安装Redis服务,请参考这篇:http://blog.csdn.net/u010648555/article/details/69944668

如果Redis服务安装到服务器上面,请修改代码中的Redis地址和端口!否则运行不起了!

运行这个类UUidGeneratorLockTest就可以看到效果!测试结果我也在readme.txt进行了总结!

如果在测试和学习的过程中有疑问,可以随时和我联系,也可以加左侧的群互相探讨!谢谢!

四:总结

这个时代,信息爆炸,各种技术博文之间互相复制,真正好的文章还是需要鉴别的!

我也要反思,自己之前也写过一些博文,也是遇到问题了,去网上搜一些解决方案,很多方案确实是理论上可以解决当前遇到的问题,当时去深究,就会发现很多的不完整性!

多思考,多测试!让代码能够更加高效和安全!

欢迎访问我的csdn博客,我们一同成长!

"不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!"

博客首页:http://blog.csdn.net/u010648555

Redisson分布式锁的简单使用的更多相关文章

  1. Redisson分布式锁实现

    转: Redisson分布式锁实现 2018年09月07日 15:30:32 校长我错了 阅读数:3303   转:分布式锁和Redisson实现 概述 分布式系统有一个著名的理论CAP,指在一个分布 ...

  2. Java使用Redisson分布式锁实现原理

    本篇文章摘自:https://www.jb51.net/article/149353.htm 由于时间有限,暂未验证 仅先做记录.有大家注意下哈(会尽快抽时间进行验证) 1. 基本用法 添加依赖 &l ...

  3. [转帖]SpringBoot集成redisson分布式锁

    SpringBoot集成redisson分布式锁 https://www.cnblogs.com/yangzhilong/p/7605807.html 前几天同事刚让增加上这一块东西. 百度查一下 啥 ...

  4. 又长又细,万字长文带你解读Redisson分布式锁的源码

    前言 上一篇文章写了Redis分布式锁的原理和缺陷,觉得有些不过瘾,只是简单的介绍了下Redisson这个框架,具体的原理什么的还没说过呢.趁年前项目忙的差不多了,反正闲着也是闲着,不如把Rediss ...

  5. Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua

    开心一刻 我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门 昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:"看咱前面,想不到这么丑都有人要." 女朋友 ...

  6. Redisson 分布式锁实现之源码篇 → 为什么推荐用 Redisson 客户端

    开心一刻 一男人站在楼顶准备跳楼,楼下有个劝解员拿个喇叭准备劝解 劝解员:兄弟,别跳 跳楼人:我不想活了 劝解员:你想想你媳妇 跳楼人:媳妇跟人跑了 劝解员:你还有兄弟 跳楼人:就是跟我兄弟跑的 劝解 ...

  7. Redisson 分布式锁源码 09:RedLock 红锁的故事

    前言 RedLock 红锁,是分布式锁中必须要了解的一个概念. 所以本文会先介绍什么是 RedLock,当大家对 RedLock 有一个基本的了解.然后再看 Redisson 中是如何实现 RedLo ...

  8. Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch

    前言 Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch. Semaphore 意思就是在分布式场景下,只有 3 个凭证,也就意味着同 ...

  9. Redisson 分布式锁实战与 watch dog 机制解读

    Redisson 分布式锁实战与 watch dog 机制解读 目录 Redisson 分布式锁实战与 watch dog 机制解读 背景 普通的 Redis 分布式锁的缺陷 Redisson 提供的 ...

随机推荐

  1. 我的acm vim 备忘

    一.從命令到編輯模式 a :当前单词后面插入Appendi :当前位置插入Inserto :当前行下新开一行插入Open new lineA :当前行尾插入AppendI :当前行首插入InsertO ...

  2. boost::pool 库速记

    使用示例 #include <functional> #include <iostream> #include <boost/pool/pool.hpp> #inc ...

  3. 深入理解JAVA I/O系列六:Linux中的IO模型(转载的文章非常值得学习)

    From:http://www.cnblogs.com/dongguacai/p/5770287.html IO模型 linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段. 这张图大 ...

  4. Httpservlet 获取json对象字符窜

    使用的是google 的json转换jar import com.google.gson.JsonObject;import com.google.gson.JsonParser; import or ...

  5. grep&正则表达式

    p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; f ...

  6. mysql中int(10)与int(11)有什么区别吗?

    先来看下面的图片 声明字段是int类型的那一刻起,int就是占四个字节,一个字节8位,也就是4*8=32,可以表示的数字个数是2的32次方(2^32 = 4 294 967 296个数字). 4 29 ...

  7. windows下使用密钥登录Linux及xshell代理转发

    1.密钥登录原理 一般我们使用xshell访问远程主机(Linux主机)时,都是先请管理员给我们开一个账户,即为我们设置一个一个用户名和对应的密码,然后我们就可以使用下面的方式登录到远程主机了: 在这 ...

  8. JAVA基础第二组(5道题)

    6.[程序6] 题目:输入两个正整数m和n,求其最大公约数和最小公倍数.        1.程序分析:利用辗除法. package com.niit.homework1; import java.ut ...

  9. 微信小程序wx.navigateTo层叠5次限制,特殊情况的建议

    小程序页面的实例使用栈的数据结构存储,栈内元素最多5个(换一种方式说,就是用户最多能点击5次返回),微信小程序能在栈中相对高层某个页面调用其他相对低层的页面实例的方法. 小程序三种页面跳转API 的区 ...

  10. 【Beta】 第四次Daily Scrum Meeting

    一.本次会议为第四次meeting会议 二.时间:10:00AM-10:20AM 地点:陆大楼 三.会议站立式照片 四.今日任务安排 成员 昨日任务 今日任务 林晓芳 查询app提醒功能模块和用户登录 ...