本文章通过两个方式实现分布式锁
第一种方式使用redis中setnx机制来实现,第二种是使用redission组件实现(目前redis官网是推荐使用的)。
第一种实现方式:
原理:
这是设置锁是用到了setnx机制来做。
所需要的maven依赖:
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
public class DistributedLock {
private static CountDownLatch countDownLatch = new CountDownLatch(100);
private Jedis jedis;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
DistributedLock lock = new DistributedLock();
lock.decrStock();
System.out.println(countDownLatch.getCount());
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
}
public void decrStock() {
if (jedis == null) {
jedis = new Jedis("填写自己的redis服务器地址", 6379);
}
String lockName = "lockName";
String value = Thread.currentThread().getName();
//上锁成功,设置过期时间主要是为了防止锁一直存在。
if ("OK".equals(jedis.set(lockName, value, "NX", "EX", 10))) {
try {
//处理业务
Long decr = jedis.decr("stock");
if (decr<0){
System.out.println("illegal stock");
return;
}
System.out.println("剩余库存:" + decr);
} catch (Exception e) {
e.printStackTrace();
}finally {
//使用lua脚本,释放锁,value为了防止其他线程释放了其他线程持有的锁
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//eval执行后会flush
jedis.eval(luaScript, Collections.singletonList(lockName), Collections.singletonList(value));
jedis.close();
}
} else {
decrStock();
}
}
}
第二种实现方式:
所需maven依赖:
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.8.2</version>
</dependency>
public class DistributedLock {
private static CountDownLatch countDownLatch = new CountDownLatch(100);
public static void main(String[] args) throws InterruptedException {
Jedis jedis = new Jedis("填写自己redis服务IP", 6379);
Config config = new Config();
config.useSingleServer().setAddress("redis://填写自己redis服务IP:6379");
RedissonClient redissonClient = Redisson.create(config);
RLock lock = redissonClient.getLock("lockName");
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 1. 最常见的使用方法
//lock.lock();
// 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
//lock.lock(10, TimeUnit.SECONDS);
// 3. 尝试加锁,最多等待2秒,上锁以后8秒自动解锁
System.out.println(Thread.currentThread().getName());
lock.lock();
Long decr = jedis.decr("stock");
System.out.println("剩余库存:" + decr);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
redissonClient.shutdown();
jedis.close();
}
}