分布式锁实现方案

什么是分布式锁

锁我们都知道是什么,在java中,提供了synchronized关键字,以及Lock接口,通过这两种形式,我们可以轻易的实现锁,但是这两种锁只能在单个JVM中 生效,而分布式锁就是能够在多个JVM中实现资源的竞争以及抢占。

为了在多个JVM中实现资源共享,我们需要引入一个第三方的一个中间件,分布式系统与这个中间件来交互,一次来实现分布式锁。

分布式锁的实现方式

  • 数据库(lock)idkeycountthreadIdtimeout
    锁的唯一key冲入次数获得锁的线程id超时时间加锁:insert into lock(key, count, threadId,timeout) values(lockKey, 1, threadId, timeout); 重入update lock set count = count +1 where key = lockKey and threadId = threadId;递减重入次数:update lock set count = count - 1 where key = lockKey and threadId = threadId;解锁:delete from lock where key = lockKey and threadId = threadId;

优点:实现简单,一般无需引入中间件

缺点:性能低,系统故障容易造成死锁

  • Redis

在redis中有很多有很多数据结构,其中string便有这个一个特性,setnx可以在key不存在的时候设置成功,通过 这个特性,我们便创建分布式锁setnx(key, value, expire);

优点:性能高,实现简单

缺点:超时时间不易设置,可能造成任务没执行完便因为锁超时导致锁被释放

  • Zookeeper在zookeeper中有临时节点和临时有序两种节点,临时节点:操作简单,但是容易产生惊群效应(所释放时,所有等待获取锁的节点都会去争抢锁)临时有序节点:实现的锁是公平锁,无惊群效应

分布式锁的成熟方案

Curaotr


    org.apache.curator
    curator-framework
    5.3.0



    org.apache.curator
    curator-recipes
    5.3.0
public class CuratorLockTest {

    //定义锁节点的路径
    private String node = "/locks";
    //设置zookeeper连接
    private final String connectString = "zookeeper1:2181,zookeeper2:2181,zookeeper3:2181";
    //设置超时时间
    private final int sessionTimeout = 2000;
    //设置超时时间
    private final int connectionTimeout = 3000;

    public static void main(String[] args) {
        new CuratorLockTest().test();
    }

    private void test() {

        final InterProcessLock lock2 = new InterProcessMutex(getCuratorFramework(), node);

        //线程2
        new Thread(new Runnable() {
            @Override
            public void run() {
                //线程加锁
                try {
                    lock2.acquire();
                    System.out.println("线程2获取到锁");

                    //线程沉睡
                    Thread.sleep(5*1000);

                    lock2.release();
                    System.out.println("线程2释放锁");

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }

    //对分布式锁进行初始化
    private CuratorFramework getCuratorFramework() {
        //重试策略,定义初试时间3s,重试3次
        ExponentialBackoffRetry exponentialBackoffRetry = new ExponentialBackoffRetry(3000, 3);

        //初始化客户端
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(connectString)
                .sessionTimeoutMs(sessionTimeout)
                .connectionTimeoutMs(connectionTimeout)
                .retryPolicy(exponentialBackoffRetry)
                .build();

        //开启连接
        client.start();
        System.out.println("zookeeper 初始化完成...");
        return client;

    }

}

Redisson

@Slf4j
public class RedissonLockTest {

    private final static String LOCK_KEY = "RESOURCE_KEY";
    int n = 500;


    public static void main(String[] args) {

    }

    public void lock() {
        RedissonClient redissonClient = redissonClient();
        //定义锁
        RLock lock = redissonClient.getLock(LOCK_KEY);
        lock.lock();
        try {
            log.info("线程:" + Thread.currentThread().getName() + "获得了锁");
            log.info("剩余数量:{}", --n);
        } catch (Exception e) {
            log.error("程序执行异常:{}", e);
        } finally {
            log.info("线程:" + Thread.currentThread().getName() + "准备释放锁");
            //释放锁
            lock.unlock();
        }
    }

    public void tryLock() {
        RedissonClient redissonClient = redissonClient();
        //定义锁
        RLock lock = redissonClient.getLock(LOCK_KEY);
        //lock.lock();
        try {
            //尝试加锁,最大等待时间300毫秒,上锁30毫秒自动解锁
            if (lock.tryLock(300, 30, TimeUnit.MILLISECONDS)) {
                log.info("线程:" + Thread.currentThread().getName() + "获得了锁");
                log.info("剩余数量:{}", --n);
            }
        } catch (Exception e) {
            log.error("程序执行异常:{}", e);
        } finally {
            log.info("线程:" + Thread.currentThread().getName() + "准备释放锁");
            //释放锁
            lock.unlock();
        }
    }

    public static RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        return Redisson.create(config);
    }
}
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章