分布式锁与实现(一)-为什么需要分布式锁

news2024/11/16 2:17:06

1 在开发中的锁是什么

在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。

在java中我们有两种资源控制方式Synchronized与AQS

1.2 基于Synchronized实现的锁控制

Synchronized是java提供的一种内置的锁机制,Synchronized的获取和释放锁由JVM实现,用户不需要显示的释放锁,非常方便。

在实际中我们使用的两种形式

  • 同步方法使用synchronized修饰方法,在调用该方法前,需要获得内置锁(java每个对象都有一个内置锁),否则就处于阻塞状态
 public synchronized void save(){//内容}
  • 同步代码块使用synchronized(object){}进行修饰,在调用该代码块时,需要获得内置锁,否则就处于阻塞状态
synchronized(object){

}

1.3 基于AQS实现的锁控制

AQS,是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。同步器的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态,在抽象方法的实现过程中免不了要对同步状态进行更改,ReentrantLock就是我们常用的AQS实现类

{
    ReentrantLock lock=new ReentrantLock();
    lock.lock();
    //内容
    lock.unlock();
}

1.3.1 公平性

ReentrantLock提供了两种公平性选择:

  • 公平性锁

在公平的锁,线程将会按照他们发出请求的顺序来获得锁。

  • 非公平性锁

在非公平的锁上,当线程申请锁时,同时锁的状态变为可用,那么线程有机会可以跳过所有等待线程并获得这个锁。

2 分布式下的挑战与分布式锁

分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

显然单个机器的线程锁无法管控多个机器对同一资源的访问,这时使用分布式锁,就可以把整个集群当作一个应用一样去处理

2.1 分布式锁需要怎么样的特性

  • (必须)分布式锁必须在多机器下保证资源,同时只有一个线程进行使用
  • (多数情况下)分布式必须保证高可用
  • (多数情况下)分布式锁获取锁和释放锁性能要好
  • (多数情况下)具备锁失效机制,在分布式锁执行者失效依然被动解锁
  • (最好)根据业务要求可以实现公平锁

3 分布式锁的实现

目前主流的分布式锁主要有3种:

  • 基于数据库实现分布式锁,这里的数据库指的是关系型数据库;
  • 基于 ZooKeeper 实现分布式锁;
  • 基于缓存实现分布式锁。

3.1 基于数据库实现分布式锁

基于数据库实现分布式锁的原理非常简单,当多个资源请求进行数据添加的时候,通过对数据库插入表内容,同时资源表的唯一约束性,会保证只有1个表数据添加成功。从而进行后续操作。数据库实现的分布式锁本身无法实现公平锁。

3.2 基于 ZooKeeper 实现分布式锁

基于ZooKeeper实现分布式锁,首先要了解ZooKeeper的节点类型,ZooKeeper支持6种数据结构,PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、EPHEMERAL_SEQUENTIAL、 CONTAINER、PERSISTENT_WITH_TTL、PERSISTENT_SEQUENTIAL_WITH_TTL,而我们用到的会是以下三种:

  • PERSISTENT

持久化目录节点,客户端与zookeeper断开连接后,该节点依旧存在

  • EPHEMERAL

临时节点,生命周期和客户端会话绑定。也就是说,如果客户端会话失效了,那么这个节点就会自动被清除掉

  • EPHEMERAL_SEQUENTIAL

临时顺序节点,生命周期和客户端会话绑定。也就是说,如果客户端会话失效了,那么这个节点就会自动被清除掉,并且在生成时会带有顺序编号。

基于ZooKeeper实现分布式锁,以资源命名持久化目录节点,通过判断是否有该持久化目录节点且在该线程生成的节点是否顺序编号最少,如果为true则可以获取资源,最终实现公平锁。而非公平锁,我们只需要以资源命名临时节点,如果临时节点不存在则可以获取资源,实现非公平锁。

3.3 基于缓存实现分布式锁

基于缓存实现的分布式锁,现在一般是指使用Redis实现的分布式锁。而Redis通常使用其setnx函数来的特性来实现锁:setnx 函数的返回值有 1 和 0

  • 返回 1,说明该服务器获得锁。
  • 返回 0,说明其他服务器已经获得了锁,进程不能进入临界区。

程序通过判断setnx的返回值判断是否取到锁。从而进行后续操作。Redis实现的分布式锁本身无法实现公平锁。

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

  • 理解容易程度  数据库\geq缓存>Zookeeper

数据库及缓存实现的方式比较直观查看返回结果即可,而基于Zookeeper实现的分布式锁首先要理解其运作方式,结合程序才能实现。

  • 实现复杂度  Zookeeper\geq缓存>数据库

 Zookeeper实现复杂性体现在对其特性的理解,Redis实现复杂性体现在保持可用性的情况下如何保持正确性.

  • 性能 缓存>Zookeeper>数据库

 存储媒介及系统本身确定。

  • 可靠性 Zookeeper>缓存>数据库

可靠性上,Zookeeper和缓存基本都能很好解决可靠性上的问题,但是准确率上Zookeeper会比缓存更好。

理解容易程度(从难到易)

数据库\geq缓存>Zookeeper 

实现复杂度(从难到易)

 Zookeeper\geq缓存>数据库

性能(从高到低)

缓存>Zookeeper>数据库

可靠性(从高到低)

可靠性 Zookeeper>缓存>数据库 

5 后记

分布式锁在分布式服务中是很常用的,在文中提到的特性也尤其重要,后续我会通过多篇博文来逐一介绍,并且深入介绍她们的实现

参考: 锁 (计算机科学)

分布式锁

分布式技术原理与算法解析-分布式协调与同步

书籍:Java并发编程实战

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175277.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JDK 8新特性之Lambda表达式

目录 一:使用匿名内部类存在的问题 Lambda表达式写法,代码如下: 二:Lambda的标准格式 三:Lambda的实现原理 四:Lambda省略格式 五:Lambda的前提条件 六:函数式接口 七:Lambd…

05回溯法

文章目录装载问题回溯算法优化算法构造最优解0-1背包问题批处理作业调度问题图的M着色问题N皇后问题最大团问题回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回&…

12. 字典dict类型详解

1. 基础知识 (1) 字典(dictionary)是Python中另一个非常有用的内置数据类型。 (2) 列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。 (3) 字典是一种映射类型&#xff…

Flowable进阶学习(三)流程、流程实例挂起与激活;启动、处理、结束流程的原理以及相关表结构与变动

文章目录流程挂起与激活流程实例挂起与激活启动、处理、结束流程的原理一、启动流程的原理启动一个流程实例时涉及到的表及表结构:ACT_RU_EXECUTION 运行时流程执行实例ACT_RU_IDENTITYLINK 运行时用户关系信息ACT_RU_TASK 运行时任务表ACT_RU_VARIABLE 运行时变量表二、处理流…

过滤器Filter总结

过滤器Filter1. 简介2. 快速入门3. 执行流程4. 使用细节4.1 拦截路径4.2 过滤器链5. 案例5.1 需求5.2 LoginFilter1. 简介 过滤器是JavaWeb三大组件之一(Servlet、Filter,Listner); 作用: 把对资源(servl…

Ubuntu22.04 安装 ssh

文章目录Ubuntu22.04 安装 ssh一、 环境配置二、 启动远程连接三、 开放端口四、 远程连接Ubuntu22.04 安装 ssh 一、 环境配置 安装 Ubuntu 系统后,我们首先需要配置管理员 root 用户: sudo passwd root然后,进行软件源的更换&#xff1a…

14 Java集合(Map集合+HashMap+泛型使用+集合面试题)

集合14.11 Map集合14.11.1 Map集合特点14.11.2 Map集合体系结构14.12 HashMap14.12.1 HashMap基本使用14.12.2 HashMap实际应用14.12.3 HashMap练习14.12.4 HashMap底层实现原理14.12.5 put的过程原码14.12.6 resize过程原码14.12.7 get的过程原码14.13 HashTable14.14 泛型高级…

5-1中央处理器-CPU的功能和基本结构

文章目录一.CPU的功能二.CPU的基本结构(一)运算器1.运算器的基本组成2.专用数据通路方式3.CPU内部单总线方式(二)控制器1.基本组成2.实现过程(三)寄存器一.CPU的功能 中央处理器(CPU&#xff0…

并查集的入门与应用

目录 一、前言 二、并查集概念 1、并查集的初始化 2、并查集的合并 3、并查集的查找 4、初始化、查找、合并代码 5、复杂度 二、路径压缩 三、例题 1、蓝桥幼儿园(lanqiaoOJ题号1135) 2、合根植物(2017年决赛,lanqiaoO…

SQL注入篇 - 布尔盲注及延时注入

数据来源 盲注 什么是盲注: 布尔盲注原理 布尔盲注流程 手工盲注思路(以下的文章参考:DVWA-sql注入(盲注) - N0r4h - 博客园) 手工盲注的过程,就像你与一个机器人聊天,这个机器人知…

DGSEA | GSEA做完了不要停,再继续比较一下有意义的通路吧!~

1写在前面 GSEA大家都会用了,但GSEA也有它自己的缺点,就是不能比较两个基因集或通路的富集情况。🤒 今天介绍一个Differential Gene Set Enrichment Analysis (DGSEA),可以量化两个基因集的相对富集程度。😉 2用到的包…

Java中的位运算及其常见的应用

文章目录1、位运算1.1 原码、反码、补码1.2 位运算符2、位运算的应用2.1 取模运算2.2 奇偶性判断2.3 交换变量的值2.4 加法运算1、位运算 1.1 原码、反码、补码 计算机中所有数据的存储和运算都是以二进制补码的形式进行的。a —> 97,A —> 65,‘…

深入学习Vue.js(十二)编译器

模板DSL的编译器 1.编译器概述 编译器实际上是一段程序,他用来将一种语言A翻译为另一种语言B。其中,A被称为源代码,B被称为目标代码。编译器将源代码翻译为目标代码的过程被称为编译。完整的编译过程通常包含词法分析、语法分析、语义分析、…

软件测试——测试用例

作者:~小明学编程 文章专栏:测试开发 格言:热爱编程的,终将被编程所厚爱。 目录 测试用例的设计方法 等价类 边界值 错误猜测法 判定表法(使用于关系组合) 设计步骤 具体例子 正交法 场景设计法…

Redis相关简介

1. Redis 简介 在这个部分,我们将学习以下3个部分的内容,分别是: ◆ Redis 简介(NoSQL概念、Redis概念) ◆ Redis 的下载与安装 ◆ Redis 的基本操作 1.1 NoSQL概念 1.1.1 问题现象 在讲解NoSQL的概念之前呢&am…

8. R语言画:散点图、直方图、条形图、箱线图、小提琴图、韦恩图

b站课程视频链接: https://www.bilibili.com/video/BV19x411X7C6?p1 腾讯课堂(最新,但是要花钱,我花99😢😢元买了,感觉讲的没问题,就是知识点结构有点乱,有点废话)&…

九大数据分析方法-综合型分析方法以及如何使用这九大分析方法

文章目录3 综合型分析方法3.1 相关性分析法3.1.1 直接相关3.1.2 间接相关3.2标签分析法3.3 MECE法4 如何使用九大方法本文来源,为接地气的陈老师的知识星球,以及付同学的观看笔记。3 综合型分析方法 3.1 相关性分析法 相关性分析法:寻找指标…

ROS2机器人编程简述humble-第二章-Executors .3.5

ROS2机器人编程简述humble-第二章-Parameters .3.4由于ROS2中的节点是C对象,因此一个进程可以有多个节点。事实上,在许多情况下,这样做是非常有益的,因为当通信处于同一进程中时,可以通过使用共享内存策略来加速通信。…

freeglut 在mfc 下的编译

freeglut 是OpenGL Utility Toolkit (GLUT) library 的替代版本,glut 应用广阔,但比较陈旧,很久没有更新。 我原来的opengl 用的是glut, 想更新到64位版本,怎么也找不到合适的下载。最后找到完全替代版本freeglut。fre…

【Linux】线程概念 | 互斥

千呼万唤始出来,终于到多线程方面的学习了! 所用系统Centos7.6 本文的源码👉【传送门】 最近主要是在我的hexo个人博客上更新,csdn的更新会滞后 文章目录1.线程的概念1.1 执行流1.2 线程创建时做了什么?1.3 内核源码中…