redis 分布式锁
基于Redisson的分布式锁一种简单实现
定义回调接口
package com.ijavoracle.common.lock;
/**
* 分布式锁回调接口
*
* @author ijavoracle
*/
public interface DistributedLockCallback<T> {
/**
* 调用者必须在此方法中实现需要加分布式锁的业务逻辑
*
* @return
*/
public T process();
/**
* 得到分布式锁名称
*
* @return
*/
public String getLockName();
}
定义分布式锁模板接口
package com.ijavoracle.common.lock;
import java.util.concurrent.TimeUnit;
/**
* 分布式锁操作模板
*
* @author ijavoracle
*/
public interface DistributedLockTemplate {
/**
* 使用分布式锁,使用锁默认超时时间。
*
* @param callback
* @return
*/
public <T> T lock(DistributedLockCallback<T> callback);
/**
* 使用分布式锁。自定义锁的超时时间
*
* @param callback
* @param leaseTime 锁超时时间。超时后自动释放锁。
* @param timeUnit
* @return
*/
public <T> T lock(DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit);
}
使用redisson最简单的Single instance mode实现分布式锁模板接口
package com.ijavoracle.common.lock;
import java.util.concurrent.TimeUnit;
import org.redisson.RedissonClient;
import org.redisson.core.RLock;
/**
* Single Instance mode 分布式锁模板
*
* @author ijavoracle
*/
public class SingleDistributedLockTemplate implements DistributedLockTemplate {
private static final long DEFAULT_TIMEOUT = 5;
private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;
private RedissonClient redisson;
public SingleDistributedLockTemplate() {
}
public SingleDistributedLockTemplate(RedissonClient redisson) {
this.redisson = redisson;
}
@Override
public <T> T lock(DistributedLockCallback<T> callback) {
return lock(callback, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
}
@Override
public <T> T lock(DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit) {
RLock lock = null;
try {
lock = redisson.getLock(callback.getLockName());
lock.lock(leaseTime, timeUnit);
return callback.process();
} finally {
if (lock != null) {
lock.unlock();
}
}
}
public void setRedisson(RedissonClient redisson) {
this.redisson = redisson;
}
}
定义spring的FactoryBean
package com.ijavoracle.common.lock;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.redisson.Config;
import org.redisson.Redisson;
import org.redisson.RedissonClient;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.Assert;
/**
* 创建分布式锁模板实例的工厂Bean
*
* @author ijavoracle
*/
public class DistributedLockFactoryBean implements FactoryBean<DistributedLockTemplate> {
private Logger logger = Logger.getLogger(DistributedLockFactoryBean.class);
private LockInstanceMode mode;
private DistributedLockTemplate distributedLockTemplate;
private RedissonClient redisson;
@PostConstruct
public void init() {
logger.debug("初始化分布式锁模板");
InputStream inputStream = null;
Config config = null;
try {
inputStream = DistributedLockFactoryBean.class.getClassLoader().getResourceAsStream("redisson-conf.json");
config = Config.fromJSON(inputStream);
} catch (IOException e) {
logger.error("读取Redisson配置失败", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
logger.error("", e);
}
}
}
Assert.notNull(config);
redisson = Redisson.create(config);
}
@PreDestroy
public void destroy() {
logger.debug("销毁分布式锁模板");
redisson.shutdown();
}
@Override
public DistributedLockTemplate getObject() throws Exception {
switch (mode) {
case SINGLE:
distributedLockTemplate = new SingleDistributedLockTemplate(redisson);
break;
}
return distributedLockTemplate;
}
@Override
public Class<?> getObjectType() {
return DistributedLockTemplate.class;
}
@Override
public boolean isSingleton() {
return true;
}
public void setMode(String mode) {
if (StringUtils.isBlank(mode)) {
throw new IllegalArgumentException("未找到dlm.redisson.mode配置项");
}
this.mode = LockInstanceMode.parse(mode);
if (this.mode == null) {
throw new IllegalArgumentException("不支持的分布式锁模式");
}
}
private enum LockInstanceMode {
SINGLE;
public static LockInstanceMode parse(String name) {
for (LockInstanceMode modeIns : LockInstanceMode.values()) {
if (modeIns.name().equals(name.toUpperCase())) {
return modeIns;
}
}
return null;
}
}
}
<bean id="distributeLockTemplate" class="com.ijavoracle.common.lock.DistributedLockFactoryBean">
<property name="mode" value="SINGLE"/>
</bean>
redisson-conf.json
{
"singleServerConfig":{
"idleConnectionTimeout":10000,
"pingTimeout":1000,
"connectTimeout":1000,
"timeout":1000,
"retryAttempts":3,
"retryInterval":1000,
"reconnectionTimeout":3000,
"failedAttempts":3,
"password":123456,
"subscriptionsPerConnection":5,
"clientName":null,
"address":[
"//10.33.40.83:6379"
],
"subscriptionConnectionMinimumIdleSize":1,
"subscriptionConnectionPoolSize":25,
"connectionMinimumIdleSize":5,
"connectionPoolSize":100,
"database":0,
"dnsMonitoring":false,
"dnsMonitoringInterval":5000
},
"threads":0,
"codec":null,
"useLinuxNativeEpoll":false,
"eventLoopGroup":null
}
测试
假如不加锁的话,各个线程的日志会混乱地输出在一起;
使用锁后,一个线程日志输出完后才会输出另一个线程的,说明锁起作用了。
package com.ijavoracle.common.lock;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hikvision.hbss.common.lock.DistributedLockCallback;
import com.hikvision.hbss.common.lock.DistributedLockTemplate;
public class DistributedLockTest {
private static DistributedLockTemplate distributedLockTemplate;
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring/common.xml");
distributedLockTemplate = ctx.getBean("distributeLockTemplate", DistributedLockTemplate.class);
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");
ctx.close();
}
static 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();
distributedLockTemplate.lock(new DistributedLockCallback<Object>() {
@Override
public Object process() {
doTask();
return null;
}
@Override
public String getLockName() {
return "MyLock";
}
});
} catch (InterruptedException ex) {
} // return;
}
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();
}
}
}
khlbat

浙公网安备 33010602011771号