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

网上有很多使用jedis实现分布式锁的文章了。redis官方推荐的分布式锁实现是基于redisson的。之前一直使用别人写的基于jedis的封装,今天自己动手写了一个简单的redisson的封装实现,Mark一下。

1、定义回调接口

package com.ijavoracle.common.lock;

/**
 * 分布式锁回调接口
 * 
 * @author ijavoracle
 */
public interface DistributedLockCallback<T> {

    /**
     * 调用者必须在此方法中实现需要加分布式锁的业务逻辑
     * 
     * @return
     */
    public T process();

    /**
     * 得到分布式锁名称
     * 
     * @return
     */
    public String getLockName();
}

2、定义分布式锁模板接口

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);
}

3、使用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;
    }

}

 

4、定义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;
        }
    }
} 

redisson-conf.json是从redisson官方直接copy过来配置信息(只改了redis服务器IP/PORT)

{
   "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
}

 

5、配置pom.xml依赖

<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.16</version>
</dependency>

<dependency>
     <groupId>org.redisson</groupId>
     <artifactId>redisson</artifactId>
     <version>2.2.15</version>
</dependency>

 

6、配置FactoryBean

<bean id="distributeLockTemplate" class="com.ijavoracle.common.lock.DistributedLockFactoryBean">
	<property name="mode" value="SINGLE"/>
</bean>

 7、测试

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();
        }
    }
}

假如不加锁的话,各个线程的日志会混乱地输出在一起;

使用锁后,一个线程日志输出完后才会输出另一个线程的,说明锁起作用了。

猜你喜欢

转载自layznet.iteye.com/blog/2307179