分布式锁的三种实现的对比

一篇文章读懂分布式锁解决并发的三种实现方式及优劣对比 点击关注,快速进阶高级架构师原创: 徐刘根分布式锁解决并发的三种实现方式在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。有的时候,我们需要保证一个方法在同 一时间内只能被同一个线程执行。在单机环境中,Java中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了。也就是说单纯的Java Api并不能提供分布式锁的能力。所以针... 阅读详情


原文: http://www.jianshu.com/p/c2b4aa7a12f1


锁是开发过程中十分常见的工具,在处理高并发请求的时候和订单数据的时候往往需要锁来帮助我们保证数据的安全。

场景1.前端点击太快,导致后端重复调用接口。两次调用一个接口,这样就会产生同一个请求执行了两次,而从用户的角度出发,他是因为太卡而点了两次,他的目标是执行一次请求。

场景2.对于高并发场景,我们往往需要引入分布式缓存,来加快整个系统的响应速度。但是缓存是有失效机制的,如果某一时刻缓存失效,而此时有大量的请求过来,那么所有的请求会瞬间直接打到DB上,那么这么大的并发量,DB可能是扛不住的。那么这里需要引入一个保护机制。当发生“缓存击穿”的时候加锁,从而保护DB不被拖垮。

看完了上面的场景,其实分布式锁的场景一直在我们身边。说分布式锁之前,应该先说一下java提供的锁,比较能单机解决的并发问题,没必要引入分布式的解决方案。

java提供了两种内置的锁的实现,一种是由JVM实现的synchronized和JDK提供的Lock,当你的应用是单机或者说单进程应用时,可以使用synchronized或Lock来实现锁。

但是,当你的应用涉及到多机、多进程共同完成时,例如现在的互联网架构,一般都是分布式的RPC框架来支撑,那么这样你的Server有多个,由于负载均衡的路由规则随机,相同的请求可能会打到不同的Server上进行处理,那么这时候就需要一个全局锁来实现多个线程(不同的进程)之间的同步。

实现全局的锁需要依赖一个第三方系统,此系统需要满足高可用、一致性比较强同时能应付高并发的请求。

常见的处理办法有三种:数据库、缓存、分布式协调系统。数据库和缓存是比较常用的,但是分布式协调系统是不常用的。

数据库实现分布式锁####

利用DB来实现分布式锁,有两种方案。两种方案各有好坏,但是总体效果都不是很好。但是实现还是比较简单的。

  1. 利用主键唯一规则:
    我们知道数据库是有唯一主键规则的,主键不能重复,对于重复的主键会抛出主键冲突异常。
    了解JDK reentrantlock的人都知道,reentrantlock是利用了OS的CAS特性实现的锁。主要是维护一个全局的状态,每次竞争锁都会CAS修改锁的状态,修改成功之后就占用了锁,失败的加入到同步队列中,等待唤醒。
    其实这和分布式锁实现方案基本是一致的,首先我们利用主键唯一规则,在争抢锁的时候向DB中写一条记录,这条记录主要包含锁的id、当前占用锁的线程名、重入的次数和创建时间等,如果插入成功表示当前线程获取到了锁,如果插入失败那么证明锁被其他人占用,等待一会儿继续争抢,直到争抢到或者超时为止。

这里我主要写了一个简单的实现:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 利用mysql实现可重入分布式锁
 */
public class MysqlprimaryLock {
    private static Connection connection;
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        String url = "jdbc:mysql://10.0.0.212:3308/dbwww_lock?user=lock_admin&password=lock123";
        try {
            connection = DriverManager.getConnection(url);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 加锁
     * @param lockID
     */
    public void lock(String lockID) {
        acquire(lockID);
    }

    /**
     * 获取锁
     * @param lockID
     * @return
     */
    public boolean acquire(String lockID) {
        String sql = "insert into test_lock('id','count','thName','addtime') VALUES (?,?,?,?)";
        while (true) {
            try {
                PreparedStatement statement = connection.prepareStatement(sql);
                statement.setString(1, lockID);
                statement.setInt(2, 1);
                statement.setLong(1, System.currentTimeMillis());
                boolean ifsucess = statement.execute();//如果成功,那么就是获取到了锁
                if (ifsucess)
                    return true;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            continue;
        }
    }

    /**
     * 超时获取锁
     * @param lockID
     * @param timeOuts
     * @return
     * @throws InterruptedException
     */
    public boolean acquire(String lockID, long timeOuts) throws InterruptedException {

        String sql = "insert into test_lock('id','count','thName','addtime') VALUES (?,?,?,?)";
        long futureTime = System.currentTimeMillis() + timeOuts;
        long ranmain = timeOuts;
        long timerange = 500;
        while (true) {
            CountDownLatch latch = new CountDownLatch(1);
            try {
                PreparedStatement statement = connection.prepareStatement(sql);
                statement.setString(1, lockID);
                statement.setInt(2, 1);
                statement.setLong(1, System.currentTimeMillis());
                boolean ifsucess = statement.execute();//如果成功,那么就是获取到了锁
                if (ifsucess)
                    return true;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            latch.await(timerange, TimeUnit.MILLISECONDS);
            ranmain = futureTime - System.currentTimeMillis();
            if (ranmain <= 0)
                break;
            if (ranmain < timerange) {
                timerange = ranmain;
            }
            continue;
        }
        return false;

    }

    /**
     * 释放锁
     * @param lockID
     * @return
     * @throws SQLException
     */
    public boolean unlock(String lockID) throws SQLException {
        String sql = "DELETE  from test_lock where id = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, lockID);
        boolean ifsucess = statement.execute();
        if (ifsucess)
            return true;
        return false;

    }

}

这里是利用主键冲突规则,加入了id','count','thName','addtime',count主要是为了重入计数,thName为了判断占用锁的线程,addtime是记录占用时间。上面代码没有实现重入的逻辑。

重入主要实现思路是,在每次获取锁之前去取当前锁的信息,如果锁的线程是当前线程,那么更新锁的count+1,并且执行锁之后的逻辑。如果不是当前锁,那么进行重试。释放的时候也要进行count-1,最后减到0时,删除锁标识释放锁。

优点:实现简单

缺点:没有超时保护机制,mysql存在单点,并发量大的时候请求量太大、没有线程唤醒机制,用异常去控制逻辑多少优点恶心。

对于超时保护:如果可能,可以采用定时任务去扫描超过一定阈值的锁,并删除。但是也会存在,锁住的任务执行时间很长,删除锁会导致并发问题。所以需要对超时时间有一个很好的预估。

对于单点问题:有条件可以搞一个主从,但是为了一个锁来搞一个主从是不是优点浪费?同时主从切换的时候系统不可用,这也是一个问题。

并发量大的时候请求量太大:因为这种实现方式是没有锁的唤醒机制的,不像reentrantlock在同步队列中的节点,可以通过唤醒来避免多次的循环请求。但是分布式环境数据库这种锁的实现是不能做到唤醒的。所以只能将获取锁的时间间隔调高,避免死循环给系统和DB带来的巨大压力。这样也牺牲了系统的吞吐量,因为总会有一定的间隔锁是空闲的。

用异常去控制逻辑多少优点恶心:就不说了,每次失败都抛异常.....

  1. 利用Mysql行锁的特性:

Mysql是有表锁、页锁和行锁的机制的,可以利用这个机制来实现锁。这里尽量使用行锁,它的吞吐量是最高的。

    /**
     * 超时获取锁
     * @param lockID
     * @param timeOuts
     * @return
     * @throws InterruptedException
     */
    public boolean acquireByUpdate(String lockID, long timeOuts) throws InterruptedException, SQLException {

        String sql = "SELECT id from test_lock where id = ? for UPDATE ";
        long futureTime = System.currentTimeMillis() + timeOuts;
        long ranmain = timeOuts;
        long timerange = 500;
        connection.setAutoCommit(false);
        while (true) {
            CountDownLatch latch = new CountDownLatch(1);
            try {
                PreparedStatement statement = connection.prepareStatement(sql);
                statement.setString(1, lockID);
                statement.setInt(2, 1);
                statement.setLong(1, System.currentTimeMillis());
                boolean ifsucess = statement.execute();//如果成功,那么就是获取到了锁
                if (ifsucess)
                    return true;
            } catch (SQLException e) {
                e.printStackTrace();
            }
            latch.await(timerange, TimeUnit.MILLISECONDS);
            ranmain = futureTime - System.currentTimeMillis();
            if (ranmain <= 0)
                break;
            if (ranmain < timerange) {
                timerange = ranmain;
            }
            continue;
        }
        return false;

    }


    /**
     * 释放锁
     * @param lockID
     * @return
     * @throws SQLException
     */
    public void unlockforUpdtate(String lockID) throws SQLException {
        connection.commit();

    }

利用for update加显式的行锁,这样就能利用这个行级的排他锁来实现分布式锁了,同时unlock的时候只要释放commit这个事务,就能达到释放锁的目的。

优点:实现简单

缺点:连接池爆满和事务超时的问题单点的问题,单点问题,行锁升级为表锁的问题,并发量大的时候请求量太大、没有线程唤醒机制。

连接池爆满和事务超时的问题单点的问题:利用事务进行加锁的时候,query需要占用数据库连接,在行锁的时候连接不释放,这就会导致连接池爆满。同时由于事务是有超时时间的,过了超时时间自动回滚,会导致锁的释放,这个超时时间要把控好。

对于单点问题:同上。

并发量大的时候请求量太大:同上。

行锁升级为表锁的问题:Mysql行锁默认需要走索引,如果不走索引会导致锁表,如果可以,在sql中可以强制指定索引。

缓存分布式锁####

缓存实现分布式锁还是比较常见的,因为缓存比较轻量,并且缓存的响应快、吞吐高。最重要的是还有自动失效的机制来保证锁一定能释放。

缓存的分布式锁主要通过Redis实现,当然其他的缓存也是可以的。关于缓存有两种实现吧:

  1. 基于SetNX实现:
    setNX是Redis提供的一个原子操作,如果指定key存在,那么setNX失败,如果不存在会进行Set操作并返回成功。我们可以利用这个来实现一个分布式的锁,主要思路就是,set成功表示获取锁,set失败表示获取失败,失败后需要重试。

具体看下代码:

import redis.clients.jedis.Jedis;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Redis分布式锁
 */
public class RedisLockTest {

    private Jedis jedisCli = new Jedis("localhost",6381);

    private int expireTime = 1;

    /**
     * 获取锁
     * @param lockID
     * @return
     */
    public boolean lock(String lockID){
        while(true){
            long returnFlag = jedisCli.setnx(lockID,"1");
            if (returnFlag == 1){
                System.out.println(Thread.currentThread().getName() + " get lock....");
                return true;
            }
            System.out.println(Thread.currentThread().getName() + " is trying lock....");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return false;
            }
        }
    }

    /**
     * 超时获取锁
     * @param lockID
     * @param timeOuts
     * @return
     */
    public boolean lock(String lockID,long timeOuts){
        long current = System.currentTimeMillis();
        long future = current + timeOuts;
        long timeStep = 500;
        CountDownLatch latch = new CountDownLatch(1);
        while(future > current){
            long returnFlag = jedisCli.setnx(lockID,"1");
            if (returnFlag == 1){
                System.out.println(Thread.currentThread().getName() + " get lock....");
                jedisCli.expire(lockID,expireTime);
                return true;
            }
            System.out.println(Thread.currentThread().getName() + " is trying lock....");
            try {
                latch.await(timeStep, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            current = current + timeStep;
        }
        return false;
    }

    public void unlock(String lockId){
        long flag = jedisCli.del(lockId);
        if (flag>0){
            System.out.println(Thread.currentThread().getName() + " release lock....");
        }else {
            System.out.println(Thread.currentThread().getName() + " release lock fail....");
        }
    }

    /**
     * 线程工厂,命名线程
     */
    public static class MyThreadFactory implements ThreadFactory{
        public static AtomicInteger count = new AtomicInteger();
        @Override
        public Thread newThread(Runnable r) {
            count.getAndIncrement();
            Thread thread = new Thread(r);
            thread.setName("Thread-lock-test "+count);
            return thread;
        }
    }

    public static void main(String args[]){
        final String lockID = "test1";
        Runnable task = () ->{
            RedisLockTest testCli = new RedisLockTest();
            testCli.lock(lockID);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            testCli.unlock(lockID);
        };

        MyThreadFactory factory = new MyThreadFactory();
        ExecutorService services = Executors.newFixedThreadPool(10);
        for (int i = 0;i<3;i++)
            services.execute(factory.newThread(task));
    }

}

看看结果:

pool-1-thread-3 is trying lock....
pool-1-thread-2 get lock....
pool-1-thread-1 is trying lock....
pool-1-thread-3 is trying lock....
pool-1-thread-2 release lock....
pool-1-thread-1 get lock....
pool-1-thread-3 is trying lock....
pool-1-thread-1 release lock....
pool-1-thread-3 get lock....
pool-1-thread-3 release lock....

可以看到,几个线程很好的进行了同步。

这种方式也是有优点和缺点:

优点:实现简单,吞吐量十分客观,对于高并发情况应付自如,自带超时保护,对于网络抖动的情况也可以利用超时删除策略保证不会阻塞所有流程。

缺点:单点问题、没有线程唤醒机制、网络抖动可能会引起锁删除失败。

对单点问题:因为redis一般都是单实例使用,那么对于单点问题,可以做一个主从。当然主从切换的时候也是不可用的,因为主从同步是异步的,可能会并发问题。如果对于主从还是不能保证可靠性的话,可以上Redis集群,对于Redis集群,因为使用了类一致性Hash算法,虽然不能避免节点下线的并发问题(当前的任务没有执行完,其他任务就开始执行),但是能保证Redis是可用的。可用性的问题是出了问题之后的备选方案,如果我们系统天天都出问题还玩毛啊,对于突发情况牺牲一两个请求还是没问题的。

对于线程唤醒机制:分布式锁大多都是这样轮训获取锁的,所以控制住你的重试频率,也不会导致负载特别高的。可能就是吞吐量低点而已。

对于锁删除失败:分布式锁基本都有这个问题,可以对key设置失效时间。这个超时时间需要把控好,过大那么系统吞吐量低,很容易导致超时。如果过小那么会有并发问题,部分耗时时间比较长的任务就要遭殃了。

基于Zookeeper的分布式锁####

Zookeeper是一个分布式一致性协调框架,主要可以实现选主、配置管理和分布式锁等常用功能,因为Zookeeper的写入都是顺序的,在一个节点创建之后,其他请求再次创建便会失败,同时可以对这个节点进行Watch,如果节点删除会通知其他节点抢占锁。

Zookeeper实现分布式锁虽然是比较重量级的,但实现的锁功能十分健全,由于Zookeeper本身需要维护自己的一致性,所以性能上较Redis还是有一定差距的。

Zookeeper实现分布式锁有几种形式,后面会单独的总结一下。

对比:####

Mysql实现比较简单,不需要引入第三个应用,但实现多少有些重,性能不是很好。
Redis的话实现比较简单,同时性能很好,引入集群可以提高可用性。同时定期失效的机制可以解决因网络抖动锁删除失败的问题,所以我比较倾向Redis实现。
Zookeeper实现是有些重的,同时我们还需要维护Zookeeper集群,实现起来还是比较复杂的,实现不好的话还会引起“羊群效应”。如果不是原有系统就依赖Zookeeper,同时压力不大的情况下。一般不使用Zookeeper实现分布式锁。



作者:一只小哈
链接:http://www.jianshu.com/p/c2b4aa7a12f1
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

【五斗米】实现分布式锁的三种方式 在单击环境下,就是只有当前JVM虚拟机A中的多个线程对同一个Object(共享资源)进行操作,可以采用同步互斥(就是只有同一时间只有一个线程对共享资源进行事务操作)的方式,我们常用的方式就是采用加锁的方式解决,虽然不能保证数据的强一致性,但是能够保证数据的最终一致性。........................ 阅读详情

相关推荐

MDM主数据清洗和编码集成说明

绝大多数的企业业务系统是伴随业务发展而建设的,但随着业务发展单一系统难以支撑企业业务闭环。MDM主数据管理平台可以满足企业数据治理的需求,本文针对主数据清洗和编码集成进行梳理。...

数通畅联 3318

SpringCloud 分布式锁的多种实现

面试必备:聊聊分布式锁的多种实现! 文章目录面试必备:聊聊分布式锁的多种实现!前言1. 分布式锁概述2. 基于数据库的分布式锁2.1 数据库悲观锁实现的分布式锁2.2 数据库乐观锁实现的分布式锁3.基于Redis实现的分布式锁3.1 setnx + expire3.2 setnx + value值是过期时间3.3 set的扩展命令(set ex px nx)3.4 set ex px nx + 校验唯一随机值,再删除3.5 Redisson3.6 Redisson + RedLock4. Zookeepe

猫头虎技术团队:授渔优于赠鱼,兴趣引领智慧,探索之乐尤显珍贵。商务合作+:Libin9iOak ,万粉变现+:优快云WF,猫头虎承诺每年免费为100名C站创作者做账号流量诊断服务!全网搜:猫头虎技术团队,点击文章底部名片或直接私信我一切皆可谈,快找虎哥! 5748

从Chiplet到UCIE:D2D互联技术如何重塑半导体设计生态

本文探讨了D2D互联技术在半导体设计中的革命性作用,从Chiplet到UCIE标准的演进如何重塑行业生态。详细分析了D2D互联的技术本质、架构选择及UCIE标准带来的变革,并展望了未来光学D2D和3D集成等趋势。高速互联接口技术的突破为AI加速器和计算芯片提供了更高带宽和能效。

weixin_29292535的博客 931

分布式锁的实现方式-面试篇

分布式锁三种实现方式,分布式锁的实现方式-面试篇

weixin_45023719的博客 2662

谷歌学术用publish-or-perish来对引用量排序

用谷歌学术搜索文献的时候发现不能按照引用量高低进行排序,网上提供了这个软件。 下载地址如下:Publish or Perish (harzing.com)https://harzing.com/resources/publish-or-perish 关于软件界面页面和各种指标的介绍,可以参考中科大的这个PPT: 文献分析软件——publish or perish(精品·公开课件).ppt (book118.com)https://max.book118.com/html/2018/1124/813

m0_48878989的博客 1万+

树莓派 SPI操作

扩展板配备一款0.96inch,128864分辨率的oled显示屏,通过SPI控制,先上显示效果图。由于程序过长,在这里我就不把代码全部贴出来了,只是简单讲解一下spi的操作函数。管脚如下如所有,左边方框的管脚分别为MOSI MISO SCLK,左边CE0,CE1为两个片选管脚,分别对应上图中的spidev0.0,spidev0.1两个设备。下载spidev库,复制到树莓派,并行运行如下命令解压安装。spi设备,此处设备为/dev/spi-decv0.0。在/dev路径下面,我们可以发现两个spi设备。

weixin_46529898的博客 914

面试必备:聊聊分布式锁的多种实现!

我们的系统都是分布式部署的,日常开发中,秒杀下单、抢购商品等等业务场景,为了防⽌库存超卖,都需要用到分布式锁。分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的系统或同一个系统的不同主机之间共享了某个临界资源,往往需要互斥来防止彼此干扰,以保证一致性。业界流行的分布式锁实现,一般有这3种方式:基于数据库实现的分布式锁基于Redis实现的分布式锁基于Zookeeper实现的分布式锁。

m0_50180963的博客 1644

STM32Cube高效开发教程<基础篇>(一)----概述

一、 STM32系列器件和开发工具发展历史声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。本专栏博客参考《STM32Cube高效开发教程(基础篇)》,有意向的读者可以购买正版书籍辅助学习,本书籍由王维波老师、鄢志丹老师、王钊老师倾力打造,书籍内容干货满满。一、 STM32系列器件和开发工具发展历史。

我的博客 1171

《面试必考》— 分布式锁实现方式

分布式锁 在应用开发中,特别是web工程开发,通常都是并发编程,不是多进程就是多线程。这种场景下极易出现线程并发性安全问题,此时不得不使用锁来解决问题。在多线程高并发场景下,为了保证资源的线程安全问题,jdk为我们提供了synchronized关键字和ReentrantLock可重入锁,但是它们只能保证一个工程内的线程安全。在分布式集群、微服务、云原生横行的当下,如何保证不同进程、不同服务、不同机器的线程安全问题,jdk并没有给我们提供既有的解决方案。此时,我们就必须借助于相关技术手动实现了。目前主流的实现

m0_68921558的博客 1182

读懂 SAP Fiori Administration Catalogs:从管理员入口、权限编排到 Spaces 和 Pages 的落地实践

SAP Fiori 管理员目录的核心价值在于为系统配置提供标准化入口,解决权限与展示分离的问题。随着 SAP_UI 7.55 版本更新,SAP_FLP_ADMIN 角色整合了关键管理工具(如 Launchpad Designer、Content Manager),并通过 Business Catalog 和 Space 的协同作用,确保管理员既能访问配置工具,又能直观查看相关功能入口。项目实施中需注意配置层级(系统级/客户端级)的选择,以及多人协作时的数据同步问题,以提升交付效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 193

【教程4>第5章>第23节】基于FPGA的Gardner环实现——环路滤波器模块和Gardner环整体测试

1]黄凌.基于FPGA的QPSK全数字调制解调系统的设计与实现[D].南京航空航天大学[2025-02-02].DOI:10.7666/d.d166927.注意,这里包括一个NCO模块,一个内插模块,一个时偏误差检测模块,一个环路滤波器模块,在gardner环中,wk的反馈输入,变量为ww,从而构成了闭环。[4]李司.基于FPGA的数字接收机同步技术的研究与实现[D].北京交通大学[2025-02-02].DOI:10.7666/d.y1082455.:调整NCO的相位步长,控制采样时刻。

FPGA/MATLAB学习教程/源码/项目合作开发 853

分布式锁三种实现方式及对比

分布式锁三种实现方式: 1. 基于数据库实现分布式锁; 2. 基于缓存(Redis等)实现分布式锁; 3. 基于Zookeeper实现分布式锁; 一, 基于数据库实现分布式锁 1. 悲观锁 利用select … where … for update 排他锁 注意: 其他附加功能与实现一基本一致,这里需要注意的是“where name=lock ”,name字段必须要走索引,否则会锁表。有些情况下,比如表不大,mysql优化器会不走这个索引,导致锁表问题。 2. 乐观锁 所谓乐观锁与前边最大

hanjiaqian的博客 412

PyTorch实战(2)——使用PyTorch构建神经网络

在本节中,我们使用 PyTorch 在简单数据集上构建了一个神经网络,训练神经网络来映射输入和输出,并通过执行反向传播来更新权重值以最小化损失值,并利用 Sequential 类简化网络构建过程;介绍了获取网络中间值的常用方法,以及如何使用 save、load 方法保存和加载模型,以避免再次训练模型。

盼小辉丶的博客 1万+

4【分布式锁的三种实现方式及对比分析】

面试了阿里、美团与滴滴后,我有了几个重大发现…>>>一、问题介绍日常工作中很多场景下需要用到分布式锁,例如:任务运行(多个节点同一时刻同一个任务只能在一个节点上运行(分片任务除外)),交易请求接收(前端交易请求发送时,可能由于两次提交,后端需要识别出这是一个交易)等,怎么样实现一个分布式锁呢?一般有:z...

小屁孩大帅-保密的博客 137

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

【Java】中分布式锁的三种实现方式及对比

分布式锁三种实现方式: 基于数据库实现分布式锁; 基于缓存(Redis等)实现分布式锁; 基于Zookeeper实现分布式锁; 一, 基于数据库实现分布式锁 悲观锁 利用select … where … for update 排他锁 注意: 其他附加功能与实现一基本一致,这里需要注意的是“where name=lock ”,name字段必须要走索引,否则会锁表。有些情况下,比如表不大,mysql优化器会不走这个索引,导致锁表问题。 乐观锁 所谓乐观锁与前边最大区别在于基于CAS思想,

JavaWebEngineer的博客 626

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

分布式锁的三种实现方式_分布式锁,三种实现方式,性能对比分析!

一、问题介绍日常工作中很多场景下需要用到分布式锁,例如:任务运行(多个节点同一时刻同一个任务只能在一个节点上运行(分片任务除外)),交易请求接收(前端交易请求发送时,可能由于两次提交,后端需要识别出这是一个交易)等,怎么样实现一个分布式锁呢?一般有:zookeeper、redis、database等三种实现方式。二、分布式锁实现1、zookeeperzookeeper实现分布式锁的原理就...

weixin_39922749的博客 289

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

分布式锁的三种实现方式及对比

分布式锁的三种实现 一、为什么要使用分布式锁 为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用Java并发处理相关的API(如ReentrantLock或Synchronized)进行互斥控制。在单机环境中,Java中提供了很多并发处理相关的API。 但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多...

sinat_27380699的博客 550

分布式锁01:分布式锁的三种实现的对比

Mysql实现比较简单,不需要引入第三个应用,但实现多少有些重,性能不是很好。 Redis的话实现比较简单,同时性能很好,引入集群可以提高可用性。同时定期失效的机制可以解决因网络抖动锁删除失败的问题,所以我比较倾向Redis实现。 Zookeeper实现是有些重的,同时我们还需要维护Zookeeper集群,实现起来还是比较复杂的,实现不好的话还会引起“羊群效应”。如果不是原有系统就...

jupiter_888的博客 120

分布式锁的三种实现方式及对比分析(代码实现细节)

一、问题介绍 日常工作中很多场景下需要用到分布式锁,例如:任务运行(多个节点同一时刻同一个任务只能在一个节点上运行(分片任务除外)),交易请求接收(前端交易请求发送时,可能由于两次提交,后端需要识别出这是一个交易)等,怎么样实现一个分布式锁呢?一般有:zookeeper、redis、database等三种实现方式。 二、分布式锁实现 2.1、zookeeper 2.1.1、原理 zook...

MayMatrix 的博客 538

三种分布式锁的实现方式对比

基于数据库实现 加锁,或类似redis记录数据。性能不好不用! 基于Redis实现 这是比较常用的一种实现方式。 通过setnx可以存入key,如果存入key成功返回1,如果存入的key已经存在了,返回0.如此可以判断key存在说明已经有节点调用,不存在说明没有节点调用。 基于ZooKeeper的实现 多个客户端(jvm),同时在zk上创建相同的一个临时节点,因为临时节点路径是保证唯一,只要谁能够...

小生的博客 357

分布式锁的三种实现方式及对比分析

Java面试笔试面经、Java技术每天学习一点公众号Java面试关注我不迷路作者:yangjianzhou来源:https://my.oschina.net/yangjianzhou一、...

java面试笔试 885

mysql可重入分布式锁_分布式锁的三种实现的对比

锁是开发过程中十分常见的工具,在处理高并发请求的时候和订单数据的时候往往需要锁来帮助我们保证数据的安全。场景1.前端点击太快,导致后端重复调用接口。两次调用一个接口,这样就会产生同一个请求执行了两次,而从用户的角度出发,他是因为太卡而点了两次,他的目标是执行一次请求。场景2.对于高并发场景,我们往往需要引入分布式缓存,来加快整个系统的响应速度。但是缓存是有失效机制的,如果某一时刻缓存失效,而此时有...

weixin_36364022的博客 314
上一篇: 分布式锁的几种实现方式~
下一篇: zookeeper来完成分布式锁的功能
还不够
博客等级 码龄16年 113粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值