标签:定时 package rgba roo 项目 redisson map its filter
在之前的项目中分布式锁和限流是基于redis进行的,分布式锁基于setnx和expire命令实现,也可以基于lua脚本实现。限流是采用固定时间窗算法进行的。
最近了解到redisson这个工具类,而且基于其分布式锁的实现是比较常见的,简单研究下其使用。
官网:wiki地址 https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95
官网解释如下:Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
pom增加:
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.15.0</version> </dependency>
增加日志文件 logback.xml
<?xml version="1.0" encoding="UTF-8" ?> <configuration scan="true" scanPeriod="60000"> <property name="LOG_HOME" value="/export/logs/cmdb/"/> <property name="APP_NAME" value="cmdb"/> <property name="LOG_FILE_EXPIRE_TIME" value="180"/> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} | ${APP_NAME} - %p | %thread | %c | line:%L - %m%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_HOME}${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>${LOG_FILE_EXPIRE_TIME}</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} | ${APP_NAME} - %p | %thread | %c | line:%L - %m%n</pattern> </encoder> </appender> <root> <level value="ERROR"/> <appender-ref ref="STDOUT"/> <!--<appender-ref ref="FILE"/>--> </root> <!-- 不同包,设置不同的日志级别 --> <logger name="com.xm.ggn" level="INFO"/> </configuration>
package com.xm.ggn.test.redisson; import lombok.extern.slf4j.Slf4j; import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import java.util.concurrent.TimeUnit; @Slf4j public class Client { private static final Long TIME_LOCKED = 50 * 1000l; private static final String KEY_LOCKED = "myLock"; private static RedissonClient redissonClient = null; public static void main(String[] args) { initRedissonClient(); lock(); } private static void initRedissonClient() { // 1. Create config object Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); // 2. Create Redisson instance Client.redissonClient = Redisson.create(config); } private static void lock() { RLock lock1 = redissonClient.getLock(KEY_LOCKED); log.error("lock1 clas: {}", lock1.getClass()); lock1.lock(); log.info("lock, ThreadName: {} id: {} locked, 重入次数: {}", Thread.currentThread().getName(), Thread.currentThread().getId(), lock1.getHoldCount()); // 处理业务逻辑 try { Thread.sleep(TIME_LOCKED); reLock(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock1.unlock(); log.info("lock, ThreadName: {} id: {} unlock, 重入次数: {}", Thread.currentThread().getName(), Thread.currentThread().getId(), lock1.getHoldCount()); } } /** * 测试锁的重入 */ private static void reLock() { RLock lock1 = redissonClient.getLock(KEY_LOCKED); lock1.lock(); log.info("reLock, ThreadName: {} id: {} locked, 重入次数: {}", Thread.currentThread().getName(), Thread.currentThread().getId(), lock1.getHoldCount()); // 处理业务逻辑 try { Thread.sleep(TIME_LOCKED); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock1.unlock(); log.info("reLock, ThreadName: {} id: {} unlock, 重入次数: {}", Thread.currentThread().getName(), Thread.currentThread().getId(), lock1.getHoldCount()); } } }
结果:
2021-02-01 16:20:23.013 | cmdb - ERROR | main | com.xm.ggn.test.redisson.Client | line:35 - lock1 clas: class org.redisson.RedissonLock 2021-02-01 16:20:23.050 | cmdb - INFO | main | com.xm.ggn.test.redisson.Client | line:37 - lock, ThreadName: main id: 1 locked, 重入次数: 1 2021-02-01 16:21:13.056 | cmdb - INFO | main | com.xm.ggn.test.redisson.Client | line:57 - reLock, ThreadName: main id: 1 locked, 重入次数: 2 2021-02-01 16:22:03.059 | cmdb - INFO | main | com.xm.ggn.test.redisson.Client | line:66 - reLock, ThreadName: main id: 1 unlock, 重入次数: 1 2021-02-01 16:22:03.061 | cmdb - INFO | main | com.xm.ggn.test.redisson.Client | line:47 - lock, ThreadName: main id: 1 unlock, 重入次数: 0
注意:
(1)redis中是通过HASH来存储锁的,key是UUID+":"+ThreadId;value 是重入的层数,例如上面过程中查看redis数据如下:
127.0.0.1:6379> hgetall myLock 1) "c20d8714-89c6-485f-ad4f-8dbb54271ebf:1" 2) "1" 127.0.0.1:6379> hgetall myLock 1) "c20d8714-89c6-485f-ad4f-8dbb54271ebf:1" 2) "2" 127.0.0.1:6379> hgetall myLock (empty list or set)
(2)也可以使用lock(long var1, TimeUnit var3); 方法自动释放锁
private static void lock3() { RLock lock1 = redissonClient.getLock(KEY_LOCKED); log.error("lock1 clas: {}", lock1.getClass()); // 500s 后自动释放锁 lock1.lock(500, TimeUnit.SECONDS); try { Thread.sleep(TIME_LOCKED); } catch (InterruptedException ignore) { // ignore } }
测试查看日志如下:
127.0.0.1:6379> ttl myLock (integer) 493 127.0.0.1:6379> hgetall myLock 1) "3cdf7b21-1e36-4f1f-b0ba-f0339286f416:1" 2) "1"
(3)tryLock(long time, TimeUnit unit) 可以尝试一定时间去获取锁,返回Boolean值
private static void lock2() { for (int i = 0; i < 3; i++) { new Thread(new Runnable() { @Override public void run() { log.info(Thread.currentThread().getName() + " \t 运行"); RLock lock1 = redissonClient.getLock(KEY_LOCKED); try { // 尝试获取锁60s boolean b = lock1.tryLock(7, TimeUnit.SECONDS); if (!b) { log.info(Thread.currentThread().getName() + " \t 获取锁失败"); return; } } catch (InterruptedException e) { } log.info(Thread.currentThread().getName() + " \t 获取锁"); try { // 模拟处理逻辑用时50s Thread.sleep(5 * 1000); } catch (InterruptedException e) { } lock1.unlock(); log.info(Thread.currentThread().getName() + " \t 释放锁"); } }).start(); } }
结果:
2021-02-01 17:17:04.915 | cmdb - INFO | Thread-3 | com.xm.ggn.test.redisson.Client | line:121 - Thread-3 运行 2021-02-01 17:17:04.915 | cmdb - INFO | Thread-1 | com.xm.ggn.test.redisson.Client | line:121 - Thread-1 运行 2021-02-01 17:17:04.915 | cmdb - INFO | Thread-2 | com.xm.ggn.test.redisson.Client | line:121 - Thread-2 运行 2021-02-01 17:17:04.949 | cmdb - INFO | Thread-1 | com.xm.ggn.test.redisson.Client | line:133 - Thread-1 获取锁 2021-02-01 17:17:09.952 | cmdb - INFO | Thread-1 | com.xm.ggn.test.redisson.Client | line:143 - Thread-1 释放锁 2021-02-01 17:17:09.954 | cmdb - INFO | Thread-3 | com.xm.ggn.test.redisson.Client | line:133 - Thread-3 获取锁 2021-02-01 17:17:11.925 | cmdb - INFO | Thread-2 | com.xm.ggn.test.redisson.Client | line:127 - Thread-2 获取锁失败 2021-02-01 17:17:14.956 | cmdb - INFO | Thread-3 | com.xm.ggn.test.redisson.Client | line:143 - Thread-3 释放锁
(4) 查看RLock的继承关系如下
默认使用的是非公平锁,不过一般情况使用的都是公平锁,也就是先到先得。
(1)默认非公平锁
private static void lock1() { for (int i = 0; i < 5; i++) { // 休眠一下使线程按照顺序启动 try { Thread.sleep(1 * 100); } catch (InterruptedException e) { } Thread thread = new Thread(new Runnable() { @Override public void run() { log.info(Thread.currentThread().getName() + " \t 运行"); // 下面方式获取到的是非公平锁 RLock lock1 = redissonClient.getLock(KEY_LOCKED); // RLock lock1 = redissonClient.getFairLock(KEY_LOCKED); log.error("lock1 clas: {}", lock1.getClass()); lock1.lock(); log.info(Thread.currentThread().getName() + " \t 获取锁"); try { Thread.sleep(TIME_LOCKED); } catch (InterruptedException e) { e.printStackTrace(); } log.info(Thread.currentThread().getName() + " \t 释放锁"); lock1.unlock(); } }); thread.setName("MyThread: " + i); thread.start(); } }
结果:
2021-02-01 17:34:02.226 | cmdb - INFO | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 0 运行 2021-02-01 17:34:02.233 | cmdb - ERROR | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:100 - lock1 clas: class org.redisson.RedissonLock 2021-02-01 17:34:02.325 | cmdb - INFO | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 1 运行 2021-02-01 17:34:02.325 | cmdb - ERROR | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:100 - lock1 clas: class org.redisson.RedissonLock 2021-02-01 17:34:02.426 | cmdb - INFO | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 2 运行 2021-02-01 17:34:02.426 | cmdb - ERROR | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:100 - lock1 clas: class org.redisson.RedissonLock 2021-02-01 17:34:02.526 | cmdb - INFO | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 3 运行 2021-02-01 17:34:02.526 | cmdb - ERROR | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:100 - lock1 clas: class org.redisson.RedissonLock 2021-02-01 17:34:02.627 | cmdb - INFO | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 4 运行 2021-02-01 17:34:02.627 | cmdb - ERROR | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:100 - lock1 clas: class org.redisson.RedissonLock 2021-02-01 17:34:16.038 | cmdb - INFO | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:103 - MyThread: 3 获取锁 2021-02-01 17:34:21.038 | cmdb - INFO | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:110 - MyThread: 3 释放锁 2021-02-01 17:34:21.043 | cmdb - INFO | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:103 - MyThread: 1 获取锁 2021-02-01 17:34:26.044 | cmdb - INFO | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:110 - MyThread: 1 释放锁 2021-02-01 17:34:26.047 | cmdb - INFO | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:103 - MyThread: 0 获取锁 2021-02-01 17:34:31.047 | cmdb - INFO | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:110 - MyThread: 0 释放锁 2021-02-01 17:34:31.050 | cmdb - INFO | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:103 - MyThread: 4 获取锁 2021-02-01 17:34:36.050 | cmdb - INFO | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:110 - MyThread: 4 释放锁 2021-02-01 17:34:36.054 | cmdb - INFO | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:103 - MyThread: 2 获取锁 2021-02-01 17:34:41.055 | cmdb - INFO | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:110 - MyThread: 2 释放锁
(2) 公平锁的使用
主要代码同上,只是获取锁变为公平锁
RLock lock1 = redissonClient.getFairLock(KEY_LOCKED);
结果:
2021-02-01 17:38:04.689 | cmdb - INFO | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 0 运行 2021-02-01 17:38:04.696 | cmdb - ERROR | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:98 - lock1 clas: class org.redisson.RedissonFairLock 2021-02-01 17:38:04.721 | cmdb - INFO | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:101 - MyThread: 0 获取锁 2021-02-01 17:38:04.787 | cmdb - INFO | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 1 运行 2021-02-01 17:38:04.787 | cmdb - ERROR | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:98 - lock1 clas: class org.redisson.RedissonFairLock 2021-02-01 17:38:04.888 | cmdb - INFO | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 2 运行 2021-02-01 17:38:04.888 | cmdb - ERROR | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:98 - lock1 clas: class org.redisson.RedissonFairLock 2021-02-01 17:38:04.989 | cmdb - INFO | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 3 运行 2021-02-01 17:38:04.989 | cmdb - ERROR | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:98 - lock1 clas: class org.redisson.RedissonFairLock 2021-02-01 17:38:05.089 | cmdb - INFO | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:96 - MyThread: 4 运行 2021-02-01 17:38:05.089 | cmdb - ERROR | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:98 - lock1 clas: class org.redisson.RedissonFairLock 2021-02-01 17:38:09.723 | cmdb - INFO | MyThread: 0 | com.xm.ggn.test.redisson.Client | line:108 - MyThread: 0 释放锁 2021-02-01 17:38:09.729 | cmdb - INFO | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:101 - MyThread: 1 获取锁 2021-02-01 17:38:14.729 | cmdb - INFO | MyThread: 1 | com.xm.ggn.test.redisson.Client | line:108 - MyThread: 1 释放锁 2021-02-01 17:38:14.732 | cmdb - INFO | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:101 - MyThread: 2 获取锁 2021-02-01 17:38:19.732 | cmdb - INFO | MyThread: 2 | com.xm.ggn.test.redisson.Client | line:108 - MyThread: 2 释放锁 2021-02-01 17:38:19.734 | cmdb - INFO | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:101 - MyThread: 3 获取锁 2021-02-01 17:38:24.734 | cmdb - INFO | MyThread: 3 | com.xm.ggn.test.redisson.Client | line:108 - MyThread: 3 释放锁 2021-02-01 17:38:24.737 | cmdb - INFO | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:101 - MyThread: 4 获取锁 2021-02-01 17:38:29.738 | cmdb - INFO | MyThread: 4 | com.xm.ggn.test.redisson.Client | line:108 - MyThread: 4 释放锁
至此简单研究下redisson分布式锁使用。一般是基于AOP自定义注解实现分布式锁。
标签:定时 package rgba roo 项目 redisson map its filter
原文地址:https://www.cnblogs.com/qlqwjy/p/14354385.html