集成Redisson和添加过滤器及红包功能
- 集成Redisson客户端并配置相关属性- 添加自定义过滤器配置和实现 - 实现红包领取功能和分布式锁测试 - 更新pom.xml,添加Redisson依赖
This commit is contained in:
parent
f768ea78f0
commit
5f2cb9f209
114
ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java
Normal file
114
ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package cn.whaifree.interview.mhy;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.0
|
||||||
|
* @Author whai文海
|
||||||
|
* @Date 2024/10/12 15:02
|
||||||
|
* @注释
|
||||||
|
*/
|
||||||
|
public class Main
|
||||||
|
{
|
||||||
|
public static void main(String args[])
|
||||||
|
{
|
||||||
|
Scanner cin = new Scanner(System.in);
|
||||||
|
int i = cin.nextInt();
|
||||||
|
int[] nums = new int[i];
|
||||||
|
for (int i1 = 0; i1 < nums.length; i1++) {
|
||||||
|
nums[i1] = cin.nextInt();
|
||||||
|
}
|
||||||
|
method(nums);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void method(int[] nums) {
|
||||||
|
int[] tmp = Arrays.copyOf(nums, nums.length);
|
||||||
|
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < nums.length - 1; i++) {
|
||||||
|
int a = i;
|
||||||
|
int b = i + 1;
|
||||||
|
if (nums[a] < 0 && nums[b] > 0) {
|
||||||
|
nums[a] = -nums[a];
|
||||||
|
nums[b] = -nums[b];
|
||||||
|
}
|
||||||
|
if (nums[a] < 0 && nums[b] < 0) {
|
||||||
|
nums[a] = -nums[a];
|
||||||
|
nums[b] = -nums[b];
|
||||||
|
}
|
||||||
|
sum += nums[a];
|
||||||
|
}
|
||||||
|
sum += nums[nums.length - 1];
|
||||||
|
|
||||||
|
nums = tmp;
|
||||||
|
int sumB = 0;
|
||||||
|
for (int i = tmp.length - 1; i > 0; i--) {
|
||||||
|
int a = i;
|
||||||
|
int b = i - 1;
|
||||||
|
if (nums[a] < 0 && nums[b] > 0) {
|
||||||
|
nums[a] = -nums[a];
|
||||||
|
nums[b] = -nums[b];
|
||||||
|
}
|
||||||
|
if (nums[a] < 0 && nums[b] < 0) {
|
||||||
|
nums[a] = -nums[a];
|
||||||
|
nums[b] = -nums[b];
|
||||||
|
}
|
||||||
|
sumB += nums[a];
|
||||||
|
}
|
||||||
|
sumB += nums[0];
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println(Math.max(sumB, sum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class p3{
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
LinkedList<Integer> lis = new LinkedList<>();
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
lis.add(i, i * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(lis.indexOf(4));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class P2{
|
||||||
|
public static void main(String args[])
|
||||||
|
{
|
||||||
|
Scanner cin = new Scanner(System.in);
|
||||||
|
int i = cin.nextInt();
|
||||||
|
LinkedList<Integer> lis = new LinkedList<>();
|
||||||
|
for (int i1 = 0; i1 < i; i1++) {
|
||||||
|
lis.add(1 + i1);
|
||||||
|
}
|
||||||
|
int x = cin.nextInt();
|
||||||
|
for (int j = 0; j < x; j++) {
|
||||||
|
int a = cin.nextInt();
|
||||||
|
int b = cin.nextInt();
|
||||||
|
int c = cin.nextInt();
|
||||||
|
method(lis, a, b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Integer li : lis) {
|
||||||
|
System.out.println(li+" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void method(LinkedList<Integer> list, int a, int b, int c) {
|
||||||
|
Integer A = list.get(list.indexOf(a));
|
||||||
|
list.remove(a - 1);
|
||||||
|
int i = list.indexOf(b);
|
||||||
|
|
||||||
|
int indexOfB = i;
|
||||||
|
if (c == 0) {
|
||||||
|
list.add(indexOfB, A);
|
||||||
|
}else {
|
||||||
|
list.add(indexOfB + 1, A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
package cn.whaifree.redo.redo_all_240924;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.0
|
||||||
|
* @Author whai文海
|
||||||
|
* @Date 2024/10/12 12:01
|
||||||
|
* @注释
|
||||||
|
*/
|
||||||
|
public class LeetCode289 {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[][] board = {{0,1,0},{0,0,1},{1,1,1},{0,0,0}};
|
||||||
|
new Solution().gameOfLife(board);
|
||||||
|
for (int i = 0; i < board.length; i++) {
|
||||||
|
System.out.println(Arrays.toString(board[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Solution {
|
||||||
|
/**
|
||||||
|
* 为了保证当前修改后的状态不会影响下一个状态的判定,设置另外的状态
|
||||||
|
* 如题所示,只有三种:
|
||||||
|
* 1. 如果当前是活细胞,但是变成了死细胞,那么设置为-1 math.abs为1
|
||||||
|
* 2. 如果当前是活细胞,仍然是活细胞,那么不变仍为1 math.abs还是1
|
||||||
|
* 3. 如果当前是死细胞,但是变成了活细胞,那么设置为2
|
||||||
|
* 那么最后遍历修改完状态之后,将-1修改回为0,2修改回为1
|
||||||
|
*
|
||||||
|
* @param board
|
||||||
|
*/
|
||||||
|
public void gameOfLife(int[][] board) {
|
||||||
|
// 设置方向来遍历某个节点周围的另外几个节点
|
||||||
|
int[] ner = new int[] { -1, 0, 1 };
|
||||||
|
// 获取行和列
|
||||||
|
int rows = board.length;
|
||||||
|
int cols = board[0].length;
|
||||||
|
// 遍历每一个节点格子
|
||||||
|
for (int row = 0; row < rows; row++) {
|
||||||
|
for (int col = 0; col < cols; col++) {
|
||||||
|
// 设置当前节点周围的存活细胞的数量
|
||||||
|
int liveNer = 0;
|
||||||
|
/**
|
||||||
|
* 当前节点是[ i , j ]
|
||||||
|
* [i-1,j-1] [i-1,j] [i-1,j+1]
|
||||||
|
* [ i ,j-1] [ i ,j] [ i ,j+1]
|
||||||
|
* [i+1,j-1] [i+1,j] [i+1,j+1]
|
||||||
|
* 那么以当前节点为中心,要求周围的节点,则最多是3*3形式
|
||||||
|
* 并且所有的行和列都是用当前节点+1或者-1或者不变构成
|
||||||
|
* 所以我们设置 ner = {-1,0,1} 来形成遍历
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
// 必须保证不计算当前节点(不计算自己)
|
||||||
|
if (!(ner[i] == 0 && ner[j] == 0)) {
|
||||||
|
// 当前节点的相邻节点坐标
|
||||||
|
int r = row + ner[i];
|
||||||
|
int c = col + ner[j];
|
||||||
|
/**
|
||||||
|
* 判断当前周围节点的存活状态,要求满足两个状态
|
||||||
|
* 1. 必须保证要在 board 矩阵中
|
||||||
|
* 2. 并且起始状态要是存活,则当前状态为1或者-1都可以(因为这两个状态都表示起始状态为活细胞)
|
||||||
|
**/
|
||||||
|
if ((r >= 0 && r < rows) && (c >= 0 && c < cols) && (Math.abs(board[r][c]) == 1)) {
|
||||||
|
liveNer++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 开始判断当前节点的存活状态
|
||||||
|
* 因为遍历到当前节点的时候,还没有开始修改细胞状态,所以还是0和1的细胞状态
|
||||||
|
* 那么只需要判断状态变化的即可,否则状态不变
|
||||||
|
**/
|
||||||
|
if ((board[row][col] == 1) && (liveNer > 3 || liveNer < 2)) {
|
||||||
|
// -1 代表这个细胞过去是活的现在死了
|
||||||
|
board[row][col] = -1;
|
||||||
|
}
|
||||||
|
if (board[row][col] == 0 && (liveNer == 3)) {
|
||||||
|
// 2 代表这个细胞过去是死的现在活了
|
||||||
|
board[row][col] = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 再把额外的状态修改回去
|
||||||
|
for (int row = 0; row < rows; row++) {
|
||||||
|
for (int col = 0; col < cols; col++) {
|
||||||
|
if (board[row][col] == 2) {
|
||||||
|
board[row][col] = 1;
|
||||||
|
}
|
||||||
|
if (board[row][col] == -1) {
|
||||||
|
board[row][col] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,18 @@
|
|||||||
<version>4.4.0</version>
|
<version>4.4.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <!– https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter –>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.redisson</groupId>-->
|
||||||
|
<!-- <artifactId>redisson-spring-boot-starter</artifactId>-->
|
||||||
|
<!-- <version>3.23.5</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<!--redisson-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson</artifactId>
|
||||||
|
<version>3.16.8</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--FastJson-->
|
<!--FastJson-->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -92,11 +104,11 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<!-- <dependency>-->
|
||||||
<groupId>org.springframework.amqp</groupId>
|
<!-- <groupId>org.springframework.amqp</groupId>-->
|
||||||
<artifactId>spring-rabbit-test</artifactId>
|
<!-- <artifactId>spring-rabbit-test</artifactId>-->
|
||||||
<scope>test</scope>
|
<!-- <scope>test</scope>-->
|
||||||
</dependency>
|
<!-- </dependency>-->
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package cn.whaifree.springdemo.config;
|
||||||
|
|
||||||
|
import cn.whaifree.springdemo.utils.Filter.SelfFilter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.0
|
||||||
|
* @Author whai文海
|
||||||
|
* @Date 2024/10/12 22:15
|
||||||
|
* @注释
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class FilterConfig {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FilterRegistrationBean<SelfFilter> customFilterRegistration() {
|
||||||
|
FilterRegistrationBean<SelfFilter> registration = new FilterRegistrationBean<>();
|
||||||
|
registration.setFilter(new SelfFilter());
|
||||||
|
registration.addUrlPatterns("/*"); // 指定过滤器应用的 URL 模式
|
||||||
|
registration.setName("customFilter");
|
||||||
|
registration.setOrder(1); // 设置过滤器的顺序
|
||||||
|
return registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.whaifree.springdemo.config;
|
||||||
|
|
||||||
|
import org.redisson.Redisson;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.redisson.config.Config;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.0
|
||||||
|
* @Author whai文海
|
||||||
|
* @Date 2024/10/12 20:56
|
||||||
|
* @注释
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class RedissonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedissonClient redissonClient() {
|
||||||
|
Config config = new Config();
|
||||||
|
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
|
||||||
|
config.setThreads(10);
|
||||||
|
RedissonClient redissonClient = Redisson.create(config);
|
||||||
|
return redissonClient;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package cn.whaifree.springdemo.controller.redEnvelope;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.redisson.api.RBucket;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.0
|
||||||
|
* @Author whai文海
|
||||||
|
* @Date 2024/10/12 20:31
|
||||||
|
* @注释
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/redEnvelope")
|
||||||
|
public class RedEnvelopeController {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping(value = "/redisson/{key}")
|
||||||
|
public String redissonTest(@PathVariable("key") String lockKey) {
|
||||||
|
RLock lock = redissonClient.getLock(lockKey);
|
||||||
|
try {
|
||||||
|
lock.lock();
|
||||||
|
Thread.sleep(10000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
return "已解锁";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("distribute")
|
||||||
|
public String rob(Double amount) {
|
||||||
|
// 构造红包数据
|
||||||
|
Map<String, Object> redPacket = new HashMap<>();
|
||||||
|
redPacket.put("amount", amount);
|
||||||
|
redPacket.put("id", System.currentTimeMillis()); // 使用当前时间戳作为红包 ID
|
||||||
|
|
||||||
|
// 存入 Redis 红包列表
|
||||||
|
RBucket<Object> redPacketList = redissonClient.getBucket("red_packet_list");
|
||||||
|
redPacketList.set(redPacket);
|
||||||
|
|
||||||
|
return "Distributed successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("rob")
|
||||||
|
public String rob(String userId) {
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package cn.whaifree.springdemo.utils.Filter;
|
||||||
|
|
||||||
|
import jakarta.servlet.*;
|
||||||
|
import jakarta.servlet.annotation.WebFilter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 1.0
|
||||||
|
* @Author whai文海
|
||||||
|
* @Date 2024/10/12 22:13
|
||||||
|
* @注释
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@WebFilter(filterName = "SelfFilter", urlPatterns = "/*")
|
||||||
|
public class SelfFilter implements Filter {
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
Filter.super.init(filterConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||||
|
System.out.println("SelfFilter doFilter");
|
||||||
|
filterChain.doFilter(servletRequest, servletResponse);
|
||||||
|
System.out.println("SelfFilter doFilter end");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
Filter.super.destroy();
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,15 @@ spring:
|
|||||||
port: 6379
|
port: 6379
|
||||||
# 选择db1
|
# 选择db1
|
||||||
database: 3
|
database: 3
|
||||||
|
redis:
|
||||||
|
redisson:
|
||||||
|
file: classpath:redisson.yaml
|
||||||
|
|
||||||
|
|
||||||
|
rabbitmq:
|
||||||
|
listener:
|
||||||
|
direct:
|
||||||
|
auto-startup: false
|
||||||
|
|
||||||
|
|
||||||
# springdoc-openapi项目配置
|
# springdoc-openapi项目配置
|
||||||
|
27
springDemo/src/main/resources/lua/RobEnvelope.lua
Normal file
27
springDemo/src/main/resources/lua/RobEnvelope.lua
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
local userHashKey = KEYS[1] -- 用户领取记录 Hash 表键
|
||||||
|
local redPacketListKey = KEYS[2] -- 红包列表键
|
||||||
|
local userRecordListKey = KEYS[3] -- 用户领取记录列表键
|
||||||
|
local userId = ARGV[1] -- 用户 ID
|
||||||
|
|
||||||
|
-- 检查用户是否已经领取过红包
|
||||||
|
local exists = redis.call('HEXISTS', userHashKey, userId)
|
||||||
|
if exists == 1 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 从红包列表中取出一条红包数据
|
||||||
|
local redPacketData = redis.call('RPOP', redPacketListKey)
|
||||||
|
if not redPacketData then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 解析红包数据
|
||||||
|
local redPacket = cjson.decode(redPacketData)
|
||||||
|
|
||||||
|
-- 存储用户领取记录
|
||||||
|
redis.call('HSET', userHashKey, userId, redPacketData)
|
||||||
|
|
||||||
|
-- 将红包领取信息存入用户领取记录列表
|
||||||
|
redis.call('LPUSH', userRecordListKey, redPacketData)
|
||||||
|
|
||||||
|
return redPacket
|
42
springDemo/src/main/resources/redisson.yaml
Normal file
42
springDemo/src/main/resources/redisson.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 单节点配置
|
||||||
|
singleServerConfig:
|
||||||
|
# 连接空闲超时,单位:毫秒
|
||||||
|
idleConnectionTimeout: 10000
|
||||||
|
# 连接超时,单位:毫秒
|
||||||
|
connectTimeout: 10000
|
||||||
|
# 命令等待超时,单位:毫秒
|
||||||
|
timeout: 3000
|
||||||
|
# 命令失败重试次数,如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。
|
||||||
|
# 如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。
|
||||||
|
retryAttempts: 3
|
||||||
|
# 命令重试发送时间间隔,单位:毫秒
|
||||||
|
retryInterval: 1500
|
||||||
|
# 密码
|
||||||
|
#password: redis.shbeta
|
||||||
|
# 单个连接最大订阅数量
|
||||||
|
subscriptionsPerConnection: 5
|
||||||
|
# 客户端名称
|
||||||
|
#clientName: axin
|
||||||
|
# # 节点地址
|
||||||
|
address: redis://127.0.0.1:6379
|
||||||
|
# 发布和订阅连接的最小空闲连接数
|
||||||
|
subscriptionConnectionMinimumIdleSize: 1
|
||||||
|
# 发布和订阅连接池大小
|
||||||
|
subscriptionConnectionPoolSize: 50
|
||||||
|
# 最小空闲连接数
|
||||||
|
connectionMinimumIdleSize: 32
|
||||||
|
# 连接池大小
|
||||||
|
connectionPoolSize: 64
|
||||||
|
# 数据库编号
|
||||||
|
database: 6
|
||||||
|
# DNS监测时间间隔,单位:毫秒
|
||||||
|
dnsMonitoringInterval: 5000
|
||||||
|
# 线程池数量,默认值: 当前处理核数量 * 2
|
||||||
|
#threads: 0
|
||||||
|
# Netty线程池数量,默认值: 当前处理核数量 * 2
|
||||||
|
#nettyThreads: 0
|
||||||
|
# 编码
|
||||||
|
#codec: !<org.redisson.codec.JsonJacksonCodec> {}
|
||||||
|
## 传输模式
|
||||||
|
#transportMode : "NIO"
|
||||||
|
#
|
@ -0,0 +1,58 @@
|
|||||||
|
package cn.whaifree.springdemo;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@Slf4j
|
||||||
|
class SpringDemoApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
// 注入 RedissonClient
|
||||||
|
@Autowired
|
||||||
|
RedissonClient redissonClient;
|
||||||
|
|
||||||
|
// 计数器
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() throws InterruptedException {
|
||||||
|
|
||||||
|
CountDownLatch countDownLatch = new CountDownLatch(1000);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
|
||||||
|
// 每个线程都创建自己的锁对象
|
||||||
|
// 这是基于 Redis 实现的分布式锁
|
||||||
|
Lock lock = this.redissonClient.getLock("counterLock");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 上锁
|
||||||
|
lock.lock();
|
||||||
|
|
||||||
|
// 计数器自增 1
|
||||||
|
this.count = this.count + 1;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 释放锁
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
countDownLatch.countDown();
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
countDownLatch.await();
|
||||||
|
|
||||||
|
log.info("count = {}", this.count);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user