企业网站设计行业健网站怎么做
news/
2025/10/6 5:04:49/
文章来源:
企业网站设计行业,健网站怎么做,哦咪咖网站建设,wordpress评论通知作者1. 开局在多线程环境中#xff0c;经常会碰到需要加锁的情况#xff0c;由于现在的系统基本都是集群分布式部署#xff0c;JVM的lock已经不能满足分布式要求#xff0c;分布式锁就这样产生了。。。百度一下#xff0c;网上有很多分布式锁的方案或者例子#xff0c;琳琅满…1. 开局在多线程环境中经常会碰到需要加锁的情况由于现在的系统基本都是集群分布式部署JVM的lock已经不能满足分布式要求分布式锁就这样产生了。。。百度一下网上有很多分布式锁的方案或者例子琳琅满目看了之后不知所措总体来说有以下几种基于数据库基于zookeeper基于redis基于memcached各有优缺点和实现难度这里就不一一分析。本文主要是基于redis的setnx实现分布式锁比较简单有一定的局限性欢迎大家提出意见建议2. 加锁过程执行redis的setnx只有key不存在才能set成功(实际使用的是set(key, value, NX, EX, seconds)redis较新版本支持)如果set成功(同时也设置了key的过期时间)则表示加锁成功如果set失败则每次sleep(x)毫秒后不断尝试直到成功或者超时3. 释放过程判断加锁是否成功如果成功则执行redis的del删除4. 问题思考加锁时锁的redis key过期时间多长合适需要根据业务执行的时间长度来评估默认30秒满足绝大部分需求支持动态修改加锁时重试超时时间多长合适本文设置的是过期时间的1.2倍目的是在最坏的情况下等待锁过期后尽量保证获取到锁否则抛出超时异常。这个设置不完全合理加锁时重试的sleep时间多长合适本文采用的是随机[50-300)毫秒避免出现大量线程同时竞争目的是错峰吧释放时如何避免释放了其他线程的锁(A获取锁后由于挂起导致锁到期自动释放此时B获取到锁而A又恢复运行释放了B的锁)在初始化锁时生个一个唯一字符串作为redis锁的valuevalue一致时表明是自己的锁可以释放5. 上代码用法RedisLock lock new RedisLock(redisHelper, lockKey);try {// 执行加锁防止并发问题lock.tryLock();// do somethingsdoSomethings()}finally {// 释放锁lock.release();}RedisLock实现(注依赖RedisHepler类仅仅是对jedis的一层封装可自行实现)import org.slf4j.Logger;import org.slf4j.LoggerFactory;/*** RedisLock** version 2017-9-21上午11:56:27* author xiaoyun.zeng*/public class RedisLock {private Logger logger LoggerFactory.getLogger(getClass());/*** key前缀*/private static final String PREFIX lock:;/*** 操作redis的工具类*/private RedisHelper redisHelper;/*** redis key*/private String redisKey null;/*** redis value*/private String redisValue null;/*** 锁的过期时间(秒)默认30秒防止线程获取锁后挂掉无法释放锁*/private int lockExpire 30;/*** 尝试加锁超时时间(毫秒)默认为expire的1.2倍*/private int tryTimeout lockExpire * 1200;/*** 尝试加锁次数计数器*/private long tryCounter 0;/*** 加锁成功标记*/private boolean success false;private long startMillis 0;private long expendMillis 0;/*** RedisLock** param redisHelper* param lockKey*/public RedisLock(RedisHelper redisHelper, String lockKey) {this.redisHelper redisHelper;this.redisKey PREFIX lockKey;// 生成redis value用于释放锁时比对是否属于自己的锁// 生成规则 lockKey时间戳随机数避免重复// 乐观地认为// 1、同一毫秒内随机数相同的概率极小// 2、释放非自己线程锁的几率极小(release方法有说明这种情况)this.redisValue lockKey - System.currentTimeMillis() - this.random(10000);}/*** RedisLock** param redisHelper* param lockKey* param expire*/public RedisLock(RedisHelper redisHelper, String lockKey, int lockExpire) {this(redisHelper, lockKey);// 过期时间this.lockExpire lockExpire;// 超时时间(毫秒)默认为expire的1.2倍this.tryTimeout lockExpire * 1200;}/*** 尝试加锁* * 尝试加锁的过程将会一直阻塞下去直到加锁成功或超时** version 2017-9-21下午12:00:07* author xiaoyun.zeng* return*/public void tryLock() throws RuntimeException {startMillis System.currentTimeMillis();// 首次直接请求加锁if (!lock()) {do {// 超时判断避免永远获取不到锁的情况下一直尝试// 超时抛出runtime异常if (System.currentTimeMillis() - startMillis tryTimeout) {throw new RuntimeException(尝试加锁超时 tryTimeout ms);}// 随机休眠[50-300)毫秒// 避免出现大量线程同时竞争try {Thread.sleep(this.random(250) 50);}catch (InterruptedException e) {// 出现异常直接抛出throw new RuntimeException(e);}}while (!lock());}}/*** 释放锁** version 2017-9-21下午12:00:21* author xiaoyun.zeng* param lockKey*/public void release() {// 加锁成功才执行释放if (success) {// 释放前检查redis value是否一致// 避免A获取锁后由于挂起导致锁到期自动释放// 此时B获取到锁而A又恢复运行释放了B的锁String value redisHelper.get(redisKey);if (redisValue.equals(value)) {redisHelper.del(redisKey);logger.debug(已释放锁{}, redisValue);}}}/*** 加锁** version 2017-9-21下午6:25:58* author xiaoyun.zeng* param key* param value* param lockExpire* return*/private boolean lock() {// 加锁计数器1tryCounter;// 调用redis setnx完成加锁返回true表示加锁成功否则失败success redisHelper.setNx(redisKey, redisValue, lockExpire);// 计算总耗时expendMillis System.currentTimeMillis() - startMillis;// 记录日志if (success) {logger.debug(加锁成功尝试{}次耗时{}ms{}, tryCounter, expendMillis, redisValue);}return success;}/*** 产生随机数** version 2017-9-22上午10:05:52* author xiaoyun.zeng* param max* return*/private int random(int max) {return (int) (Math.random() * max);}}6. 测试代码单元测试RunWith(SpringRunner.class)SpringBootTestpublic class RedisLockTest {Autowiredprivate RedisHelper redisHelper;Testpublic void test() {for (int i 0; i 10; i) {new Thread(new Runnable() {Overridepublic void run() {RedisLock lock new RedisLock(redisHelper, zxy);try {lock.tryLock();try {Thread.sleep(2 * 1000);}catch (InterruptedException e) {e.printStackTrace();}}finally {lock.release();}}}).start();}while(true) {}}}日志输出2017/10/12 17:47:28.335 [Thread-8] DEBUG [RedisLock.161] 加锁成功尝试1次耗时4mszxy-1507801648330-66652017/10/12 17:47:30.340 [Thread-8] DEBUG [RedisLock.137] 已释放锁zxy-1507801648330-66652017/10/12 17:47:30.351 [Thread-14] DEBUG [RedisLock.161] 加锁成功尝试12次耗时2018mszxy-1507801648333-68662017/10/12 17:47:32.356 [Thread-14] DEBUG [RedisLock.137] 已释放锁zxy-1507801648333-68662017/10/12 17:47:32.396 [Thread-11] DEBUG [RedisLock.161] 加锁成功尝试22次耗时4065mszxy-1507801648331-52172017/10/12 17:47:34.400 [Thread-11] DEBUG [RedisLock.137] 已释放锁zxy-1507801648331-52172017/10/12 17:47:34.430 [Thread-12] DEBUG [RedisLock.161] 加锁成功尝试39次耗时6098mszxy-1507801648332-77082017/10/12 17:47:36.433 [Thread-12] DEBUG [RedisLock.137] 已释放锁zxy-1507801648332-77082017/10/12 17:47:36.453 [Thread-17] DEBUG [RedisLock.161] 加锁成功尝试50次耗时8119mszxy-1507801648334-23622017/10/12 17:47:38.457 [Thread-17] DEBUG [RedisLock.137] 已释放锁zxy-1507801648334-23622017/10/12 17:47:38.494 [Thread-9] DEBUG [RedisLock.161] 加锁成功尝试57次耗时10164mszxy-1507801648330-70862017/10/12 17:47:40.497 [Thread-9] DEBUG [RedisLock.137] 已释放锁zxy-1507801648330-70862017/10/12 17:47:40.587 [Thread-13] DEBUG [RedisLock.161] 加锁成功尝试70次耗时12254mszxy-1507801648333-88812017/10/12 17:47:42.590 [Thread-13] DEBUG [RedisLock.137] 已释放锁zxy-1507801648333-88812017/10/12 17:47:42.611 [Thread-15] DEBUG [RedisLock.161] 加锁成功尝试82次耗时14276mszxy-1507801648335-25092017/10/12 17:47:44.614 [Thread-15] DEBUG [RedisLock.137] 已释放锁zxy-1507801648335-25092017/10/12 17:47:44.699 [Thread-16] DEBUG [RedisLock.161] 加锁成功尝试89次耗时16365mszxy-1507801648334-57912017/10/12 17:47:46.702 [Thread-16] DEBUG [RedisLock.137] 已释放锁zxy-1507801648334-57912017/10/12 17:47:46.802 [Thread-10] DEBUG [RedisLock.161] 加锁成功尝试106次耗时18471mszxy-1507801648331-73472017/10/12 17:47:48.805 [Thread-10] DEBUG [RedisLock.137] 已释放锁zxy-1507801648331-7347
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928998.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!