springBoot整合redisson、TaskExecutor
前言
Redisson - 是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象,本文使用的是哨兵模式;TaskExecutor线程池想必不用多说了。
提示:以下是本篇文章正文内容,下面案例可供参考
一、Redisson
- 添加依赖
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.17.3</version> </dependency>
- 添加配置类
import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration public class RedissonConfig { @Value("${spring.redis.password}") private String password; @Value("${spring.redis.sentinel.master}") private String masterName; @Value("${spring.redis.sentinel.nodes}") private String sentinelNodes; @Bean public RedissonClient redissonClient() { Config config = new Config(); String[] nodesArr = sentinelNodes.split(","); config.useSentinelServers() .setMasterName(masterName) //可以用"rediss://"来启用SSL连接 .addSentinelAddress("redis://" + nodesArr[0], "redis://" + nodesArr[1], "redis://" + nodesArr[2]) .setPassword(password); return Redisson.create(config); } }
二、TaskExecutor
- 配置文件
略过 - 配置类
import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync @Slf4j public class ThreadConfig { @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数 executor.setCorePoolSize(5); // 设置最大线程数 executor.setMaxPoolSize(20); // 设置队列容量 executor.setQueueCapacity(100); // 设置线程活跃时间(秒) executor.setKeepAliveSeconds(100); // 设置默认线程名称 executor.setThreadNamePrefix("Executor-"); // 设置拒绝策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池 executor.setWaitForTasksToCompleteOnShutdown(true); log.info("创建一个线程池 corePoolSize is [" + 5 + "] maxPoolSize is [" + 20 + "] queueCapacity is [" + 100 + "] keepAliveSeconds is [" + 100 + "] namePrefix is [" + "Executor-" + "]."); return executor; } }
三、测试
测试类
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.task.TaskExecutor;
@Slf4j
@SpringBootTest
public class RedissonThreadTest {
@Autowired
private RedissonClient redissonClient;
@Autowired
private TaskExecutor executor;
@Test
public void readData() {
String key = "00";
String s = redissonClient.getBucket(key).get().toString();
// boolean delete = redissonClient.getBucket(key).delete();
System.out.println(s);
}
@Test
public void writeData() {
String key = "maotaijiu";
String value = "1";
redissonClient.getBucket(key).set(value);
}
@Test
public void forData() {
String key = "maotaijiu1";
String value = "100";
redissonClient.getBucket(key).set(value);
for (int i = 1; i <= 200; i++) {
executor.execute(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
seckillMaotai7(key);
});
}
}
@Test
public void seckillMaotai7(String mtKey) {
String lockKey = "lockKey";
RLock lock = redissonClient.getLock(lockKey);
System.out.println("线程名称:" + Thread.currentThread().getName()+"ok1");
//加锁
lock.lock();
System.out.println("线程名称:" + Thread.currentThread().getName()+"ok2");
try {
Integer count = Integer.parseInt(redissonClient.getBucket(mtKey).get().toString());
//如果还有库存
if (count > 0) {
// Thread.sleep(5);
//抢到了茅台,库存减一
redissonClient.getBucket(mtKey).set(count - 1);
//后续操作 do something
System.out.println("线程名称:" + Thread.currentThread().getName()+"我抢到茅台" + count + "了!");
return;
} else {
System.out.println("线程名称:" + Thread.currentThread().getName()+"卖完了,下次再来");
return;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
System.out.println("线程名称:" + Thread.currentThread().getName()+"线程名称:" + Thread.currentThread().getName()+"释放锁");
}
System.out.println("dont get lock");
return;
}
}
四、线程池要点
线程池处理任务流程:
当往线程池中提交新任务时,线程池主要流程如下:核心线程数 -> 线程队列 -> 最大线程数 -> 拒绝策略
- 如果池中任务数 < corePoolSize (核心线程数),创建新线程立即执行任务
- 如果池中任务数 > corePoolSize,新任务放到缓存队列当中等待执行
- 队列满,线程数量<maxPoolSize,新建线程立即执行任务
- 队列满,线程数量>=maxPoolSize,使用拒绝策略拒绝
拒绝策略:
ThreadPoolExecutor.AbortPolicy | ThreadPoolExecutor 默认策略 直接抛出java.util.concurrent.RejectedExecutionException异常 | |
ThreadPoolExecutor.DiscardPolicy | 放弃当前任务,并且不会抛出任何异常 | |
ThreadPoolExecutor.DiscardOldestPolicy | 会将队列中最早添加的元素移除,再尝试添加,如果失败则按该策略不断重试 | |
ThreadPoolExecutor.CallerRunsPolicy |
|
总结
可不容易呢,搞了两天