参考链接:https://blog.csdn.net/Evankaka/article/details/70568951
基于参考文章自己敲了一遍,基本一样。
利用springboot搭建环境,基于redis实现乐观锁秒杀
配置文件
#redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.timeout=10000
配置类
@Component
@ConfigurationProperties(prefix="spring.redis")
@Data
public class RedisConfig {
private String host;
private int port;
private String password;
private int timeout;
private int maxActive;
private int maxIdle;
private int maxWait;
{
maxActive = 10000;
maxIdle = 10000;
maxWait = 20;
}
}
@Configuration
public class RedisUtil {
@Autowired
private RedisConfig redisConfig;
@Bean
public JedisPool jedisPoolFactory(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisConfig.getMaxIdle());
poolConfig.setMaxTotal(redisConfig.getMaxActive());
poolConfig.setMaxWaitMillis(redisConfig.getMaxWait());
JedisPool jp = new JedisPool(poolConfig,redisConfig.getHost(),redisConfig.getPort(),
redisConfig.getTimeout(),redisConfig.getPassword(),0);
return jp;
}
public void show(){
System.out.println(redisConfig);
}
public static void returnToPool(Jedis jedis){
if(jedis != null){
jedis.close();
}
}
}
实现类:
@SpringBootTest
class OptimisticLockTest {
@Autowired
JedisPool jedisPool;
@Test
public void test(){
initProduct();
initClient();
printResult();
}
public void show(){
System.out.println(jedisPool.getResource());
}
//初始化库存
public void initProduct(){
int productNum = 100;//商品个数
String key = "pNum";
String clientList = "clientList";
Jedis jedis = jedisPool.getResource();
if(jedis.exists(clientList)){
jedis.del(clientList);
}
if (jedis.exists(key)){
jedis.del(key);
}
jedis.set(key,String.valueOf(productNum));
RedisUtil.returnToPool(jedis);
}
//初始化客户端并开始抢商品
public void initClient(){
ExecutorService threadPool = Executors.newFixedThreadPool(1000);
int clientNum = 10000;//客户端数量
for (int i = 0; i < clientNum; i++) {
threadPool.execute(new ClientThread(i));
}
threadPool.shutdown();
while(true){
if (threadPool.isTerminated()){
System.out.println("********一切都结束了********");
break;
}
try{
TimeUnit.SECONDS.sleep(1);
}catch(Exception e){
e.printStackTrace();
}
}
}
//输出结果
public void printResult() {
Jedis jedis = jedisPool.getResource();
Set<String> set = jedis.smembers("clientList");
int i = 1;
for (String value : set) {
System.out.println("第" + i++ + "个抢到商品,"+value + " ");
}
RedisUtil.returnToPool(jedis);
}
//顾客线程,设置成内部类是为了在这里也能用到jedisPool
class ClientThread implements Runnable{
private Jedis jedis = null;
private String key = "pNum";// 商品主键
private String clientList = "clientList"; 抢购到商品的顾客列表主键
private String clientName;
public ClientThread(int i){
clientName = "编号" + i +"顾客";
}
@Override
public void run() {
while(true){
try {
Thread.sleep((int)(Math.random()*5000));
} catch (InterruptedException e) {}
System.out.println(clientName + "开始抢购商品");
jedis = jedisPool.getResource();
if(jedis == null){
break;
}
try{
jedis.watch(key);
int pNum = Integer.parseInt(jedis.get(key));
if(pNum > 0){
Transaction transaction = jedis.multi();
transaction.set(key,String.valueOf(pNum-1));
List<Object> result = transaction.exec();
if(result == null || result.isEmpty()){
System.out.println("悲剧了,顾客:" + clientName + "没有抢到商品,再试亿次");// 可能是watch-key被外部修改,或者是数据操作被驳回
}else{
jedis.sadd(clientList, clientName);// 抢到商品记录一下
System.out.println("恭喜顾客:" + clientName + "抢到商品");
break;
}
}else{
System.out.println("悲剧了,库存为0,顾客:" + clientName + "没有抢到商品");
break;
}
}catch(Exception e){
e.printStackTrace();
}finally{
jedis.unwatch();
RedisUtil.returnToPool(jedis);
}
}
}
}
}