1、线程不安全,使用synchronized 单体程序可以保证线程安全,但分布式下也是线程不安全的
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/lock")
public Result lock() {
Integer stock = (Integer) redisTemplate.opsForValue().get("stock");
if (stock > 0) {
stock = stock - 1;
redisTemplate.opsForValue().set("stock", stock);
System.out.println("剩余库存: " + stock);
} else {
System.out.println("扣减失败" + stock);
}
return Result.success("操作成功");
}
2、分布式锁、redis setnx
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/lock")
public Result lock() {
Boolean result = redisTemplate.opsForValue().setIfAbsent(LOCKKEY, "paulson");
if (!result) {
return Result.fail("分布式锁占用中");
}
Integer stock = (Integer) redisTemplate.opsForValue().get("stock");
if (stock > 0) {
stock = stock - 1;
redisTemplate.opsForValue().set("stock", stock);
System.out.println("剩余库存: " + stock);
} else {
System.out.println("扣减失败" + stock);
}
redisTemplate.delete(LOCKKEY);
return Result.success("操作成功");
}
注意:1、业务异常,没有删除 key 导致死锁
解决方案: try finally
3、分布式锁
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/lock")
public Result lock() {
try {
Boolean result = redisTemplate.opsForValue().setIfAbsent(LOCKKEY, "paulson");
if (!result) {
return Result.fail("分布式锁占用中");
}
Integer stock = (Integer) redisTemplate.opsForValue().get("stock");
if (stock > 0) {
stock = stock - 1;
redisTemplate.opsForValue().set("stock", stock);
System.out.println("剩余库存: " + stock);
} else {
System.out.println("扣减失败" + stock);
}
} finally{
// 释放分布式锁
redisTemplate.delete(LOCKKEY);
}
return Result.success("操作成功");
}
注意:服务器挂掉,重启,导致没有执行delete
解决方案:设置锁的生效时间
4、分布式锁
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/lock")
public Result lock() {
try {
Boolean result = redisTemplate.opsForValue().setIfAbsent(LOCKKEY, "paulson", 10, TimeUnit.SECONDS);
if (!result) {
return Result.fail("分布式锁占用中");
}
Integer stock = (Integer) redisTemplate.opsForValue().get("stock");
if (stock > 0) {
stock = stock - 1;
redisTemplate.opsForValue().set("stock", stock);
System.out.println("剩余库存: " + stock);
} else {
System.out.println("扣减失败" + stock);
}
} finally {
// 释放分布式锁
redisTemplate.delete(LOCKKEY);
}
return Result.success("操作成功");
}
注意:超时时间应该设置多久,还是执行结束就释放掉了
解决方案:只释放自己加的锁
5、分布式锁
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private IdWorker idWorker;
@GetMapping("/lock")
public Result lock() {
String clientId = idWorker.nextId() + "";
try {
Boolean result = redisTemplate.opsForValue().setIfAbsent(LOCKKEY, clientId, 10, TimeUnit.SECONDS);
if (!result) {
return Result.fail("分布式锁占用中");
}
Integer stock = (Integer) redisTemplate.opsForValue().get("stock");
if (stock > 0) {
stock = stock - 1;
redisTemplate.opsForValue().set("stock", stock);
System.out.println("剩余库存: " + stock);
} else {
System.out.println("扣减失败" + stock);
}
} finally {
// 释放分布式锁,只释放自己创建的锁
if (clientId.equals(redisTemplate.opsForValue().get(LOCKKEY))) {
redisTemplate.delete(LOCKKEY);
}
}
return Result.success("操作成功");
}
6、使用 redisson
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.2</version>
</dependency>
compile 'org.redisson:redisson:3.13.2'
@Bean
public Redisson redisson() {
// 单机模式
Config config = new Config();
config.useSingleServer().setAddress("redis://10.179.229.187:6379").setDatabase(1);
return (Redisson) Redisson.create(config);
}
@Autowired
private Redisson redisson;
@GetMapping("/deduct_lock2")
public Result redissonLock() {
RLock lock = redisson.getLock(LOCKKEY);
try {
lock.tryLock(30, TimeUnit.SECONDS);
Integer stock = (Integer) redisTemplate.opsForValue().get("stock");
if (stock > 0) {
stock = stock - 1;
redisTemplate.opsForValue().set("stock", stock);
System.out.println("剩余库存: " + stock);
} else {
System.out.println("扣减失败" + stock);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放分布式锁,只释放自己创建的锁
lock.unlock();
}
return Result.success("操作成功");
}