redis 分布式锁

基于Redisson的分布式锁一种简单实现

基于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();  
        }  
    }  
}  
posted @ 2020-09-25 16:22  khlbat  阅读(109)  评论(0)    收藏  举报