redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放.

直接上java代码, 如下:

package com.test;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * 简单的单实例redis分布式锁
 * 没有实现的高级功能:锁的重入、锁的续约等
 *
 * @Author:tt
 * @Description:
 * @CreateTime:2019/6/12
 */
public class SingleRedisLock {

    private JedisPool jedisPool;

    /**
     * 获取锁
     *
     * @param lockKey          锁的key
     * @param lockVal          锁的val,可以利用来实现"避免误删别人锁"、"锁的重入"等功能
     * @param lockMaxLifeTime  锁的最大生命时长,到期自动销毁,单位:毫秒
     * @param tryWaitingTime   等待获取锁的超时时间,单位:毫秒
     * @param waitingSleepTime 等待获取锁的阻塞周期,单位:毫秒,设置过短会造成cpu竞争,设置过长会造成浪费,需依赖于'具体业务平均的执行时长'
     * @return
     */
    public Boolean tryLock(String lockKey, String lockVal, int lockMaxLifeTime, int tryWaitingTime, int waitingSleepTime) {

        //lua脚本,让逻辑简单清晰,同时保证原子性
        //setNX:成功-1,失败-0
        String lua = " if redis.call('set',KEYS[1],ARGV[1],'PX',ARGV[2],'NX') then return 1 else return 0 end ";

        //获取锁的开始时间
        Long tryBeginTime = System.currentTimeMillis();

        //轮询
        while (true) {

            Long result = null;
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                result = (Long) jedis.eval(lua, Arrays.asList(lockKey), Arrays.asList(lockVal, String.valueOf(lockMaxLifeTime)));
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    try {
                        jedis.close();
                    } catch (Exception e) {
                    }
                }
            }

            //获取锁成功
            if (Long.valueOf(1).equals(result)) {
                return true;
            }

            //当前时间
            Long now = System.currentTimeMillis();
            //获取等待超时,就不用获取了
            if (now - tryBeginTime >= tryWaitingTime) {
                return false;
            }

            try {
                //阻塞等一会儿再重新去获取
                TimeUnit.MILLISECONDS.sleep(waitingSleepTime);
            } catch (InterruptedException e) {
            }

        }

    }

    /**
     * 释放锁
     *
     * @param lockKey
     * @param lockVal
     * @return
     */
    public void releaseLock(String lockKey, String lockVal) {

        //如果lockVal是自己的再删除,防止误删,场景来源:当前锁的持有者操作时间太长,锁已经自动释放并被别人占有了
        String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]) end ";

        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.eval(lua, Arrays.asList(lockKey), Arrays.asList(lockVal));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                try {
                    jedis.close();
                } catch (Exception e) {
                }
            }
        }

    }

    //测试
    public static void main(String[] args) {
        //连接池
        JedisPool jedisPool = new JedisPool(new GenericObjectPoolConfig(), "127.0.0.1", 6379, 2000, "test123");
        SingleRedisLock simpleRedisLock = new SingleRedisLock();
        simpleRedisLock.jedisPool = jedisPool;

        //模拟10个并发
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {

                String lockKey = "TEST_LOCK_KEY";
                String threadName = Thread.currentThread().getName();

                //获取锁
                Boolean locked = simpleRedisLock.tryLock(lockKey, threadName,
                        30000, 5000, 200);

                //获取锁失败
                if (!locked) {
                    System.err.println(">>> " + threadName + " 获取锁失败");
                    return;
                }

                //获取锁成功,模拟执行业务操作
                System.out.println(">>> " + threadName + " 获取锁成功");
                doShortBusiness();
                //doLongBusiness();

                //释放锁
                simpleRedisLock.releaseLock(lockKey, threadName);

            }).start();
        }

        try {
            TimeUnit.MILLISECONDS.sleep(60000);
        } catch (InterruptedException e) {
        }
    }

    //短任务:100毫秒
    static void doShortBusiness() {
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
        }
    }

    //长任务:3秒
    static void doLongBusiness() {
        try {
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException e) {
        }
    }

}

锁的高级功能包含锁的重入、锁的续约等, 当然为了保证锁的高可用, redis还有主从、集群等部署方式, 对应的锁的实现也有区别, 略微复杂, 不过有现成的框架可供我们参考使用, 比较知名的如Redisson, 一个强大的redis客户端, 当然包括对“分布式锁”的完美实现, 其支持redis单实例、哨兵、集群等模式。

单实例redis分布式锁的简单实现的更多相关文章

  1. Redis分布式锁实现简单秒杀功能

    这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服 ...

  2. redis 分布式锁的简单使用

    RedisLock--让 Redis 分布式锁变得简单 目录 1. 项目介绍 2. 快速使用 2.1 引入 maven 坐标 2.2 注册 RedisLock 2.3 使用 3. 参与贡献 4. 联系 ...

  3. springmvc单Redis实例实现分布式锁(解决锁超时问题)

    一.前言 关于redis分布式锁, 查了很多资料, 发现很多只是实现了最基础的功能, 但是, 并没有解决当锁已超时而业务逻辑还未执行完的问题, 这样会导致: A线程超时时间设为10s(为了解决死锁问题 ...

  4. 自己写了个简单的redis分布式锁【我】

    自己写了个简单的redis分布式锁 [注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用] package redis; import java.util.Collection ...

  5. .NetCore使用Redis,StackExchange.Redis队列,发布与订阅,分布式锁的简单使用

    环境:之前一直是使用serverStack.Redis的客服端,今天来使用一下StackExchange.Redis(个人感觉更加的人性化一些,也是免费的,性能也不会差太多),版本为StackExch ...

  6. Redis分布式锁实例

    maven依赖 <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</ ...

  7. Redis分布式锁

    Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...

  8. Redlock(redis分布式锁)原理分析

    Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...

  9. Redlock:Redis分布式锁最牛逼的实现

    普通实现 说道Redis分布式锁大部分人都会想到:setnx+lua,或者知道set key value px milliseconds nx.后一种方式的核心实现命令如下: - 获取锁(unique ...

随机推荐

  1. 当你买了一辆全车搭载Android操作系统的某侠电动汽车以后

    前两天,小编的朋友圈被号称"中国特斯拉"的某侠超级电动跑车刷爆了.秉着喷喷更健康的精神.小编来为大家讲述一下.假设你买了一辆全车搭载着Android操作系统的某侠电动车,可能会遇 ...

  2. webservice Connection timed out

    webservice Connection timed out,当发生webservice的链接超时错误时.我想原因无非就是webclient到webservice之间的链接通路发生了异常,那么该怎样 ...

  3. nginx-tomcat负载均衡redis-session共享,静态资源分离

    nginx-tomcat负载均衡redis-session共享.静态资源分离 基本环境: redis-2.8 apache-tomcat-6.0.41 nginx1.6.2 1.redis配置 1,配 ...

  4. LeetCode 438. Find All Anagrams in a String (在字符串中找到所有的变位词)

    Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings ...

  5. unable to execute dex: multiple dex files Cocos2dxAccelerometer

    原文转载:http://discuss.cocos2d-x.org/t/conversion-to-dalvik-format-failed-unable-to-execute-dex-multipl ...

  6. 如何删除 mac 系统信息下的安装记录

    方法:在finder中:Command+Shift+G 打开 /Library/Receipts/InstallHistory.plist 所有的记录都在 InstallHistory.plist 文 ...

  7. 基于二叉搜索树的符号表和BST排序

    原代码例如以下: #include <stdlib.h> #include <stdio.h> //#define Key int typedef int Key; struc ...

  8. unity3D游戏开发实战原创视频讲座系列11之相扑游戏开发并公布到Win\WP8

     解说文件夹 第一讲 游戏的演示和资源介绍 第二讲 场景的建设 第三讲 玩家的移动 第四讲 对手的AI(让对手动起来) 第五讲 游戏的管理(上) 第六讲 游戏的管理(下) 第七讲 公布到Win8系 ...

  9. 适合国内网速的CDH5安装

    0.集群规划 说明:因为CDH能够方便的动态加入删除主机,动态改变主机上的服务,所以后面再对各机器上跑得服务进行分配. 共三台机器 操作系统: centos6.5 机器名:work01.work02. ...

  10. Python:SMOTE算法——样本不均衡时候生成新样本的算法

    Python:SMOTE算法 直接用python的库, imbalanced-learn imbalanced-learn is a python package offering a number ...