分布式锁理解与学习

本文介绍了分布式锁的概念,包括其作用和在分布式系统中的重要性。文章详细探讨了数据库、Redis和Zookeeper三种实现分布式锁的方案,分析了各自的优缺点,并通过实例解释了如何使用Redisson和Zookeeper实现分布式锁。最后总结了各种方案的适用场景和特性。
摘要由CSDN通过智能技术生成

1 分布式锁介绍

1.1 什么是分布式

一个大型的系统往往被分为几个子系统来做,一个子系统可以部署在一台机器的多个 JVM(java虚拟机) 上,也可以部署在多台机器上。但是每一个系统不是独立的,不是完全独立的。需要相互通信,共同实现业务功能。

一句话来说:分布式就是通过计算机网络将后端工作分布到多台主机上,多个主机一起协同完成工作。

1.2 什么是锁--作用安全

现实生活中,当我们需要保护一样东西的时候,就会使用锁。例如门锁,车锁等等。很多时候可能许多人会共用这些资源,就会有很多个钥匙。但是有些时候我们希望使用的时候是独自不受打扰的,那么就会在使用的时候从里面反锁,等使用完了再从里面解锁。这样其他人就可以继续使用了。

JAVA程序中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量,而同步的本质是通过锁来实现的。如 Java 中 synchronize 是在对象头设置标记,Lock 接口的实现类基本上都只是某一个 volitile 修饰的 int 型变量其保证每个线程都能拥有对该 int 的可见性和原子修改

1.3 什么是分布式锁

任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。CAP

当在分布式模型下,数据只有一份(或有限制),此时需要利用锁的技术控制某一时刻修改数据的进程数。

分布式锁: 在分布式环境下,多个程序/线程都需要对某一份(或有限制)的数据进行修改时,针对程序进行控制,保证同一时间节点下,只有一个程序/线程对数据进行操作的技术。

1.4 分布式锁具备的条件

  • 互斥性:同一时刻只能有一个服务(或应用)访问资源,特殊情况下有读写锁

  • 原子性:一致性要求保证加锁和解锁的行为是原子性的

  • 安全性:锁只能被持有该锁的服务(或应用)释放,避免死锁

  • 容错性:在持有锁的服务崩溃时,锁仍能得到释放避免死锁

  • 可重用性:同一个客户端获得锁后可递归调用---重入锁和不可重入锁

  • 公平性:看业务是否需要公平,避免饿死--公平锁和非公平锁

  • 支持阻塞和非阻塞:和 ReentrantLock 一样支持 lock 和 trylock 以及 tryLock(long timeOut)---阻塞锁和非阻塞锁==PS:::自旋锁==

  • 高可用:获取锁和释放锁 要高可用

  • 高性能:获取锁和释放锁的性能要好

  • 持久性:锁按业务需要自动续约/自动延期

2.分布式锁的解决方案

2.1 数据库实现分布式锁

2.1.1 基于数据库表实现

准备工作:创建tb_program表,用于记录当前哪个程序正在使用数据

CREATE TABLE `tb_program` (
  `program_no` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '程序的编号'
  PRIMARY KEY (`program_no`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

实现步骤:

  1. 程序访问数据时,将程序的编号(insert)存入tb_program表;

  1. 当insert成功,代表该程序获得了锁,即可执行逻辑;

  1. 当program_no相同的其他程序进行insert是,由于主键冲突会导致insert失败,则代表获取锁失败;

  1. 获取锁成功的程序在逻辑执行完以后,删除该数据,代表释放锁。

2.1.2 基于数据库的排它锁实现

除了可以通过增删操作数据表中的记录以外,其实还可以借助数据中自带的锁来实现分布式的锁。我们还用刚刚创建的那张数据库表,基于MySql的InnoDB引擎(MYSQL的引擎种类)可以通过数据库的排他锁来实现分布式锁。

实现步骤:

  1. 在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁

  1. 获得排它锁的线程即可获得分布式锁,执行方法的业务逻辑

  1. 执行完方法之后,再通过connection.commit();操作来释放锁。

实现代码

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.itheima</groupId>
    <artifactId>mysql-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--依赖包-->
    <dependencies>
      
        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.32</version>
        </dependency>

        <!-- Test dependencies -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Book

public class Book {

    // 图书ID
    private Integer id;
    // 图书名称
    private String name;
    // 图书价格
    private Float price;
    // 图书图片
    private String pic;
    // 图书描述
    private String desc;
}

BookDao

public interface BookDao {

    /**
     * 查询所有的book数据
     * @return
     */
    List<
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值