「java分布式锁教程」java 基于数据库做分布式锁

博主:adminadmin 2023-03-22 03:26:07 779

本篇文章给大家谈谈java分布式锁教程,以及java 基于数据库做分布式锁对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

java 链接redis 怎么加锁

我介绍一下Redis分布式锁吧:

一、定义redis实现分布式锁的接口

[java] view plain copy print?

package com.iol.common.util.concurrent.locks;  

  

import java.io.Serializable;  

  

/** 

 * Description: 定义redis实现分布式锁的算法br / 

 * This program is protected by copyright IOL_SMALL_TAIL.br / 

 * Program Name: IOL_SMALL_TAILbr / 

 * Date: 2015年11月8日 

 * 

 * @author 王鑫 

 * @version 1.0 

 */  

public interface IRedisLockArithmetic extends Serializable {  

    /** 

     * 加锁算法br / 

     * @param key 

     * @return 

     */  

    public boolean lock(String key);  

      

    /** 

     * 解锁算法br / 

     * @param key 

     * @return 

     */  

    public boolean unLock(String key);  

}

二、redis分布式锁基础算法实现

[java] view plain copy print?

package com.iol.common.util.concurrent.locks.arithmetic;  

  

import org.slf4j.Logger;  

import org.slf4j.LoggerFactory;  

  

import com.iol.common.util.concurrent.locks.IRedisComponent;  

import com.iol.common.util.concurrent.locks.IRedisLockArithmetic;  

  

/** 

 * Description: redis分布式锁基础算法实现br / 

 * This program is protected by copyright IOL_SMALL_TAIL.br / 

 * Program Name: IOL_SMALL_TAILbr / 

 * Date: 2015年11月9日 

 * 

 * @author 王鑫 

 * @version 1.0 

 */  

public class RedisLockBaseArithmetic implements IRedisLockArithmetic {  

    /** 

     *serialVersionUID 

     */  

    private static final long serialVersionUID = -8333946071502606883L;  

      

    private Logger logger = LoggerFactory.getLogger(RedisLockBaseArithmetic.class);  

  

    /** 

     * redis操作方法 

     */  

    private IRedisComponent redisComp;  

      

    /** 

     * 超时时间,以毫秒为单位br / 

     * 默认为5分钟 

     */  

    private long overtime = 5 * 60 * 1000L;  

      

    /** 

     * 休眠时长,以毫秒为单位br / 

     * 默认为100毫秒 

     */  

    private long sleeptime = 100L;  

      

    /** 

     * 当前时间 

     */  

    private long currentLockTime;  

      

    /** 

     * @param redisComp the redisComp to set 

     */  

    public void setRedisComp(IRedisComponent redisComp) {  

        this.redisComp = redisComp;  

    }  

  

    /** 

     * @param overtime the overtime to set 

     */  

    public void setOvertime(long overtime) {  

        this.overtime = overtime;  

    }  

  

    /** 

     * @param sleeptime the sleeptime to set 

     */  

    public void setSleeptime(long sleeptime) {  

        this.sleeptime = sleeptime;  

    }  

  

    /* (non-Javadoc) 

     * @see com.iol.common.util.concurrent.locks.IRedisLockArithmetic#lock(java.lang.String, java.lang.Long) 

     */  

    @Override  

    public boolean lock(String key) {  

        while(true) {  

            // 当前加锁时间  

            currentLockTime = System.currentTimeMillis();  

              

            if(redisComp.setIfAbsent(key, currentLockTime)) {  

                // 获取锁成功  

                logger.debug("直接获取锁{key: {}, currentLockTime: {}}", key, currentLockTime);  

                return true;  

            } else {  

                //其他线程占用了锁  

                logger.debug("检测到锁被占用{key: {}, currentLockTime: {}}", key, currentLockTime);  

                Long otherLockTime = redisComp.get(key);  

                if(otherLockTime == null) {  

                    // 其他系统释放了锁  

                    // 立刻重新尝试加锁  

                    logger.debug("检测到锁被释放{key: {}, currentLockTime: {}}", key, currentLockTime);  

                    continue;  

                } else {  

                    if(currentLockTime - otherLockTime = overtime) {  

                        //锁超时  

                        //尝试更新锁  

                        logger.debug("检测到锁超时{key: {}, currentLockTime: {}, otherLockTime: {}}", key, currentLockTime, otherLockTime);  

                        Long otherLockTime2 = redisComp.getAndSet(key, currentLockTime);  

                        if(otherLockTime2 == null || otherLockTime.equals(otherLockTime2)) {  

                            logger.debug("获取到超时锁{key: {}, currentLockTime: {}, otherLockTime: {}, otherLockTime2: {}}", key, currentLockTime, otherLockTime, otherLockTime2);  

                            return true;  

                        } else {  

                            sleep();  

                            //重新尝试加锁  

                            logger.debug("重新尝试加锁{key: {}, currentLockTime: {}}", key, currentLockTime);  

                            continue;  

                        }  

                    } else {  

                        //锁未超时  

                        sleep();  

                        //重新尝试加锁  

                        logger.debug("重新尝试加锁{key: {}, currentLockTime: {}}", key, currentLockTime);  

                        continue;  

                    }  

                }  

            }  

        }  

    }  

  

    /* (non-Javadoc) 

     * @see com.iol.common.util.concurrent.locks.IRedisLockArithmetic#unLock(java.lang.String) 

     */  

    @Override  

    public boolean unLock(String key) {  

        logger.debug("解锁{key: {}}", key);  

        redisComp.delete(key);  

        return true;  

    }  

      

    /** 

     * 休眠br / 

     * @param sleeptime 

     */  

    private void sleep() {  

        try {  

            Thread.sleep(sleeptime);  

        } catch (InterruptedException e) {  

            throw new LockException("线程异常中断", e);  

        }  

    }  

}

求java高级培训视频,全套的

蚂蚁课堂(每特学院)第一期-Java高端培训视频教程 主讲老师余胜军百度网盘免费资源在线学习 

链接:

提取码: pm4w 

蚂蚁课堂(每特学院)第一期-Java高端培训视频教程 主讲老师余胜军 35.微信 34.使用SpringClout+SpringBoot+微服务电商项目 0033-每特教育(蚂蚁课堂)-Java培训就业典礼第二天(分布式事物解决方案).zip 0032-每特学院(蚂蚁课堂)-Java培优结业典礼第一天(面试题回顾).zip 0031-每特学院(蚂蚁课堂)-MySQL优化之分表分库与读写分离.zip 0030-每特学院(蚂蚁课堂)-MySQL优化之SQL语句调优.zip 0029-每特教育(蚂蚁课堂)-MySQL优化之索引实现原理.zip 0028-每特教育(蚂蚁课堂)-MySQL优化入门.zip 0027-每特教育(蚂蚁课堂)-垃圾回收机制算法.zip 0026-每特教育(蚂蚁课堂)-深入理解Java虚拟机.zip 0025-每特教育(蚂蚁课堂)-分布式定时job-xxljob.zip 0024-每特教育(蚂蚁课堂)-Dubbo.zip 0023-每特教育(蚂蚁课堂)-Zookeeper实战分布式锁.zip 0022-每特教育(蚂蚁课堂)-SpringCloud.zip  

分布式锁--Redis秒杀(互斥锁)(一)

中秋佳节,进行月饼秒杀,特价,限量1000份,不限每人秒的份数,不要超卖即可。

RedisLock.java

ResultEnum.java

KeyUtil.java

2)无解锁

3)解锁

使用Redisson实现分布式锁

Redisson的分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口,同时还支持自动过期解锁。

Redisson同时还为分布式锁提供了异步执行的相关方法:

Redisson分布式可重入公平锁也是实现了java.util.concurrent.locks.Lock接口的一种RLock对象。在提供了自动过期解锁功能的同时,保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。

Redisson同时还为分布式可重入公平锁提供了异步执行的相关方法:

Redisson的RedissonMultiLock对象可以将多个RLock对象关联为一个联锁,每个RLock对象实例可以来自于不同的Redisson实例。

Redisson的RedissonRedLock对象实现了 Redlock 介绍的加锁算法。该对象也可以用来将多个RLock

对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例。

Redisson的分布式可重入读写锁RReadWriteLock Java对象实现了java.util.concurrent.locks.ReadWriteLock接口。同时还支持自动过期解锁。该对象允许同时有多个读取锁,但是最多只能有一个写入锁。

Redisson的分布式信号量(Semaphore)Java对象RSemaphore采用了与java.util.concurrent.Semaphore相似的接口和用法。

Redisson的可过期性信号量(PermitExpirableSemaphore)实在RSemaphore对象的基础上,为每个信号增加了一个过期时间。每个信号可以通过独立的ID来辨识,释放时只能通过提交这个ID才能释放。

Redisson的分布式闭锁(CountDownLatch)Java对象RCountDownLatch采用了与java.util.concurrent.CountDownLatch相似的接口和用法。

Redisson 分布式锁和同步器

分布式锁有哪些?

单体架构的应用可以直接使用synchronized或者ReentrantLock就可以解决多线程资源竞争的问题。如果公司业务发展较快,可以通过部署多个服务节点来提高系统的并行处理能力。由于本地锁的作用范围只限于当前应用的线程。高并发场景下,集群中某个应用的本地锁并不会对其它应用的资源访问产生互斥,就会产生数据不一致的问题,所以分布锁就派上了用场。

利用select … where … for update 排他锁

所谓乐观锁与前边最大区别在于基于CAS思想,是不具有互斥性,不会产生锁等待而消耗资源,操作过程中认为不存在并发冲突,只有update version失败后才能觉察到。我们的抢购、秒杀就是用了这种实现以防止超卖。通过增加递增的版本号字段实现乐观锁

思路: 另启一个服务,利用jdk并发工具来控制唯一资源,如在服务中维护一个concurrentHashMap,其他服务对某个key请求锁时,通过该服务暴露的端口,以网络通信的方式发送消息,服务端解析这个消息,将concurrentHashMap中的key对应值设为true,分布式锁请求成功,可以采用基于netty通信调用,当然你想用java的bio、nio或者整合dubbo、spring cloud feign来实现通信也没问题

在高并发场景下,应用程序在执行过程中往往会受到网络、CPU、内存等因素的影响,所以实现一个线程安全的分布式组件,往往需要考虑很多case,这个分布式锁有 3 个重要的考量点:

下面是redis分布式锁的各种实现方式和缺点,按照时间的发展排序:

直接利用setnx,执行完业务逻辑后调用del释放锁,简单粗暴!

为了改正第一个方法的缺陷,我们用setnx获取锁,然后用expire对其设置一个过期时间,如果服务挂了,过期时间一到自动释放

redis官方为了解决第二种方式存在的缺点,在2.8版本为set指令添加了扩展参数nx和ex,保证了setnx+expire的原子性,使用方法:set key value ex 5 nx

上面所说的第一个缺点,没有特别好的解决方法,只能把过期时间尽量设置的长一点,并且最好不要执行耗时任务 第二个缺点,可以理解为当前线程有可能会释放其他线程的锁,那么问题就转换为保证线程只能释放当前线程持有的锁,即setnx的时候将value设为任务的唯一id,释放的时候先get key比较一下value是否与当前的id相同,是则释放,否则抛异常回滚,其实也是变相地解决了第一个问题

我们可以用lua来写一个getkey并比较的脚本,jedis/luttce/redisson对lua脚本都有很好的支持

为了解决上面提到的redis集群中的分布式锁问题,redis的作者antirez的提出了red lock的概念,假设集群中所有的n个master节点完全独立,并且没有主从同步,此时对所有的节点都去setnx,并且设置一个请求过期时间re和锁的过期时间le,同时re必须小于le(可以理解,不然请求3秒才拿到锁,而锁的过期时间只有1秒也太蠢了),此时如果有n / 2 + 1个节点成功拿到锁,此次分布式锁就算申请成功

ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:

(1)redis set px nx + 唯一id + lua脚本

综上所得:

没有绝对完美的实现方式,具体要选择哪一种分布式锁,需要结合每一种锁的优缺点和业务特点而定。

关于java分布式锁教程和java 基于数据库做分布式锁的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。