创建支持并发的分布式锁

使用redlock实现分布式锁

redlock简介

在不同进程需要互斥的访问共享资源时,分布式锁是一种非常有用的技术手段。实现高效的分布式锁有三个方面需要考虑:
a.安全性:互斥,在任何时候,只有一个客户端持有锁
b.效率:不会出现死锁(一个客户端阻塞后,持有的锁无法释放)
c.容错:只要大多数redis节点能够正常工作,客户端都能获取和释放锁
redlock是redis官方提出的实现分布式锁管理器的算法。

java中如何使用redlock实现分布式锁

a.在pom文件中引入redis和redisson依赖:

<!-- redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.3.2</version>
</dependency>

b.创建获取锁后,进行业务处理的接口类

/**
获取锁后需要处理的逻辑

public interface AquiredLockWorker<T> {
T invokeAfterLockAquire() throws Exception;
}

c.创建获取锁的接口类

获取锁的接口类

public interface DistributedLocker {
/**
获取锁
@param resourceName  锁的名称
@param worker 获取锁后的处理类
@param <T>
@return 处理完具体的业务逻辑要返回的数据
@throws UnableToAquireLockException
@throws Exception
/
<T> T lock(String resourceName, AquiredLockWorker<T> worker) throws UnableToAquireLockException, Exception;

<T> T lock(String resourceName, AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception;
}

d.创建获取锁失败的异常类

/**
获取锁失败的异常类
/

public class UnableToAquireLockException extends RuntimeException {

public UnableToAquireLockException() {
}

public UnableToAquireLockException(String message) {
super(message);
}

public UnableToAquireLockException(String message, Throwable cause) {
super(message, cause);
}
}

e.创建获取redis连接的连接类

/**
获取RedissonClient连接类
/

@Component
public class RedissonConnector {
RedissonClient redisson;
@PostConstruct
public void init(){
redisson = Redisson.create();
}

public RedissonClient getClient(){
return redisson;
}
}

f.创建获取锁的实现类

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

@Component
public class RedisLocker  implements DistributedLocker{

private final static String LOCKER_PREFIX = "lock:";

@Autowired
RedissonConnector redissonConnector;
@Override
public <T> T lock(String resourceName, AquiredLockWorker<T> worker) throws InterruptedException, UnableToAquireLockException, Exception {

return lock(resourceName, worker, 100);
}

@Override
public <T> T lock(String resourceName, AquiredLockWorker<T> worker, int lockTime) throws UnableToAquireLockException, Exception {
RedissonClient redisson= redissonConnector.getClient();
RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);
// Wait for 100 seconds and automatically unlock it after lockTime
boolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);
if (success) {
try {
return worker.invokeAfterLockAquire();
} finally {
lock.unlock();
}
}
throw new UnableToAquireLockException();
}
}

g.创建测试类

public class Test {
    @Autowired
    RedisLocker distributedLocker;
     @RequestMapping(value = "/redlock")
    public String testRedlock() throws Exception{

CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(5);
for (int i = 0; i < 5; ++i) { // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
}
startSignal.countDown(); // let all threads proceed
doneSignal.await();
System.out.println("All processors done. Shutdown connection");
return "redlock";
}

class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;

Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}

public void run() {
try {
startSignal.await();
distributedLocker.lock("test",new AquiredLockWorker<Object>() {

@Override
public Object invokeAfterLockAquire() {
doTask();
return null;
}

});
}catch (Exception e){

}
}

void doTask() {
System.out.println(Thread.currentThread().getName() + " start");
Random random = new Random();
int _int = random.nextInt(200);
System.out.println(Thread.currentThread().getName() + " sleep " + _int + "millis");
try {
Thread.sleep(_int);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end");
doneSignal.countDown();
}
}
}

测试结果:
Thread-48 start
Thread-48 sleep 99millis
Thread-48 end
Thread-49 start
Thread-49 sleep 118millis
Thread-49 end
Thread-52 start
Thread-52 sleep 141millis
Thread-52 end
Thread-50 start
Thread-50 sleep 28millis
Thread-50 end
Thread-51 start
Thread-51 sleep 145millis
Thread-51 end
从运行结果看,在异步任务的情况下,只有在获取锁之后才能运行线程。

Java经验分享网

来自:http://www.javagogo.cn/article/41

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值