Java高级工程师必看系列,已拿到offer

1.为什么要使用分布式锁

使用分布式锁的目的,无外乎就是保证同一时间只有一个客户端可以对共享资源进行操作。

1.1举一个很长的例子

系统 A 是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会给用户下单。由于系统有一定的并发,所以会预先将商品的库存保存在 Redis 中,用户下单的时候会更新 Redis 的库存。此时系统架构如下:

但是这样一来会产生一个问题:假如某个时刻,Redis 里面的某个商品库存为 1。

此时两个请求同时到来,其中一个请求执行到上图的第 3 步,更新数据库的库存为 0,但是第 4 步还没有执行。

而另外一个请求执行到了第 2 步,发现库存还是 1,就继续执行第 3 步。这样的结果,是导致卖出了 2 个商品,然而其实库存只有 1 个。

很明显不对啊!这就是典型的库存超卖问题。此时,我们很容易想到解决方案:用锁把 2、3、4 步锁住,让他们执行完之后,另一个线程才能进来执行第 2 步。

按照上面的图,在执行第 2 步时,使用 Java 提供的 Synchronized 或者 ReentrantLock 来锁住,然后在第 4 步执行完之后才释放锁。

这样一来,2、3、4 这 3 个步骤就被“锁”住了,多个线程之间只能串行化执行

当整个系统的并发飙升,一台机器扛不住了。现在要增加一台机器,如下图:

增加机器之后,系统变成上图所示,假设此时两个用户的请求同时到来,但是落在了不同的机器上,那么这两个请求是可以同时执行了,还是会出现库存超卖的问题。

因为上图中的两个 A 系统,运行在两个不同的 JVM 里面,他们加的锁只对属于自己 JVM 里面的线程有效,对于其他 JVM 的线程是无效的。

因此,这里的问题是:Java 提供的原生锁机制在多机部署场景下失效了,这是因为两台机器加的锁不是同一个锁(两个锁在不同的 JVM 里面)。

那么,我们只要保证两台机器加的锁是同一个锁,问题不就解决了吗?此时,就该分布式锁隆重登场了。

分布式锁的思路是:在整个系统提供一个全局、唯一的获取锁的“东西”,然后每个系统在需要加锁时,都去问这个“东西”拿到一把锁,这样不同的系统拿到的就可以认为是同一把锁。

至于这个“东西”,可以是 Redis、Zookeeper,也可以是数据库。此时的架构如图:

通过上面的分析,我们知道了库存超卖场景在分布式部署系统的情况下使用 Java 原生的锁机制无法保证线程安全,所以我们需要用到分布式锁的方案。

2.高效的分布式锁

在设计分布式锁的时候,应该考虑分布式锁至少要满足的一些条件,同时考虑如何高效的设计分布式锁,以下几点是必须要考虑的:

(1) 互斥

在分布式高并发的条件下,最需要保证在同一时刻只能有一个线程获得锁,这是最基本的一点。

(2) 防止死锁

在分布式高并发的条件下,比如有个线程获得锁的同时,还没有来得及去释放锁,就因为系统故障或者其它原因使它无法执行释放锁的命令,导致其它线程都无法获得锁,造成死锁。所以分布式非常有必要设置锁的有效时间,确保系统出现故障后,在一定时间内能够主动去释放锁,避免造成死锁的情况。

(3) 性能

对于访问量大的共享资源,需要考虑减少锁等待的时间,避免导致大量线程阻塞。

所以在锁的设计时,需要考虑两点。

1、 锁的颗粒度要尽量小。比如你要通过锁来减库存,那这个锁的名称你可以设置成是商品的ID,而不是任取名称。这样这个锁只对当前商品有效,锁的颗粒度小。

2、 锁的范围尽量要小。比如只要锁2行代码就可以解决问题的,那就不要去锁10行代码了。

(4) 重入

我们知道ReentrantLock是可重入锁,那它的特点就是:同一个线程可以重复拿到同一个资源的锁。重入锁非常有利于资源的高效利用。关于这点之后会做演示。

3.基于Redis实现分布式锁

3.1 使用Redis命令实现分布式锁

3.1.1加锁

加锁实际上就是在redis中,给Key键设置一个值,为避免死锁,并给定一个过期时间。

使用的命令**:SET lock_key random_value NX PX 5000**

值得注意的是:

random_value 是客户端生成的唯一的字符串。

NX 代表只在键不存在时,才对键进行设置操作。

PX 5000 设置键的过期时间为5000毫秒。

也可以使用另外一条命令:SETNX key value

只不过过期时间无法设置。

这样,如果上面的命令执行成功,则证明客户端获取到了锁。

3.1.2解锁

解锁的过程就是将Key键删除,但要保证安全性,举个例子:客户端1的请求不能将客户端2的锁给删除掉。

释放锁涉及到两条指令,这两条指令不是原子性的,需要用到redis的lua脚本支持特性,redis执行lua脚本是原子性的。脚本如下:

if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) 
elsereturn 0 
end

这种方式比较简单,但是也有一个最重要的问题:锁不具有可重入性

3.2使用Redisson实现分布式锁

3.2.1Redisson介绍

Redisson是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。充分的利用了Redis键值数据库提供的一系列优势,基于Java实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。

3.2.2Redisson简单使用

Config config = new Config(); 
config.useClusterServers() 
.addNodeAddress("redis://192.168.31.101:7001") 
.addNodeAddress("redis://192.168.31.101:7002") 
.addNodeAddress("redis://192.168.31.101:7003") 
.addNodeAddress("redis://192.168.31.102:7001") 
.addNodeAddress("redis://192.168.31.102:7002") 
.addNodeAddress("redis://192.168.31.102:7003"); RedissonClient redisson = Redisson.create(config); RLock lock = redisson.getLock("anyLock"); lock.lock(); lock.unlock(); 

只需要通过它的 API 中的 Lock 和 Unlock 即可完成分布式锁,而且考虑了很多细节:

l Redisson 所有指令都通过 Lua 脚本执行,Redis 支持 Lua 脚本原子性执行

l Redisson 设置一个 Key 的默认过期时间为 30s,但是如果获取锁之后,会有一个WatchDog每隔10s将key的超时时间设置为30s。

另外,Redisson 还提供了对 Redlock 算法的支持,它的用法也很简单:

RedissonClient redisson = Redisson.create(config); 
RLock lock1 = redisson.getFairLock("lock1"); 
RLock lock2 = redisson.getFairLock("lock2"); 
RLock lock3 = redisson.getFairLock("lock3"); 
RedissonRedLock multiLock = new RedissonRedLock(lock1, lock2, lock3); 
multiLock.lock(); multiLock.unlock(); 

3.2.3Redisson原理分析

(1) 加锁机制

线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。

线程去获取锁,获取失败: 一直通过while循环尝试获取锁,获取成功后,执行lua脚本,保存数据到redis数据库。

(2) WatchDog自动延期机制

在一个分布式环境下,假如一个线程获得锁后,突然服务器宕机了,那么这个时候在一定时间后这个锁会自动释放,也可以设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生。但是在实际情况中会有一种情况,业务处理的时间可能会大于锁过期的时间,这样就可能**导致解锁和加锁不是同一个线程。**所以WatchDog作用就是Redisson实例关闭前,不断延长锁的有效期。

如果程序调用加锁方法显式地给了有效期,是不会开启后台线程(也就是watch dog)进行延期的,如果没有给有效期或者给的是-1,redisson会默认设置30s有效期并且会开启后台线程(watch dog)进行延期

多久进行一次延期:(默认有效期/3),默认有效期可以设置修改的,即默认情况下每隔10s设置有效期为30s

(3) 可重入加锁机制

Redisson可以实现可重入加锁机制的原因:

l Redis存储锁的数据类型是Hash类型

l Hash数据类型的key值包含了当前线程的信息

下面是redis存储的数据

这里表面数据类型是Hash类型,Hash类型相当于我们java的 <key,<key1,value>> 类型,这里key是指 ‘redisson’

它的有效期还有9秒,我们再来看里们的key1值为078e44a3-5f95-4e24-b6aa-80684655a15a:45它的组成是:

guid + 当前线程的ID。后面的value是就和可重入加锁有关。value代表同一客户端调用lock方法的次数,即可重入计数统计。

举图说明

上面这图的意思就是可重入锁的机制,它最大的优点就是相同线程不需要在等待锁,而是可以直接进行相应操作。

3.2.4 获取锁的流程

其中的指定字段也就是hash结构中的field值(构成是uuid+线程id),即判断锁是否是当前线程

3.2.5 加锁的流程

3.2.6 释放锁的流程

4. 使用Redis做分布式锁的缺点

Redis有三种部署方式

l 单机模式

l Master-Slave+Sentienl选举模式

l Redis Cluster模式

如果采用单机部署模式,会存在单点问题,只要 Redis 故障了。加锁就不行了

采用 Master-Slave 模式,加锁的时候只对一个节点加锁,即便通过 Sentinel 做了高可用,但是如果 Master 节点故障了,发生主从切换,此时就会有可能出现锁丢失的问题。

基于以上的考虑,Redis 的作者也考虑到这个问题,他提出了一个 RedLock 的算法。

这个算法的意思大概是这样的:假设 Redis 的部署模式是 Redis Cluster,总共有 5 个 Master 节点。

通过以下步骤获取一把锁:

  • 获取当前时间戳,单位是毫秒。
  • 轮流尝试在每个 Master 节点上创建锁,过期时间设置较短,一般就几十毫秒。
  • 尝试在大多数节点上建立一个锁,比如 5 个节点就要求是 3 个节点(n / 2 +1)。
  • 客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了。
  • 要是锁建立失败了,那么就依次删除这个锁。
  • 只要别人建立了一把分布式锁,你就得不断轮询去尝试获取锁。

但是这样的这种算法,可能会出现节点崩溃重启,多个客户端持有锁等其他问题,无法保证加锁的过程一定正确。例如:

假设一共有5个Redis节点:A, B, C, D, E。设想发生了如下的事件序列:

(1)客户端1成功锁住了A, B, C,获取锁成功(但D和E没有锁住)。

(2)节点C崩溃重启了,但客户端1在C上加的锁没有持久化下来,丢失了。

(3)节点C重启后,客户端2锁住了C, D, E,获取锁成功。

这样,客户端1和客户端2同时获得了锁(针对同一资源)。

最后

即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!

资料领取方式:蓝色传送门

我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:

Dubbo面试专题

JVM面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Java并发面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Kafka面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MongDB面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MyBatis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

MySQL面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Netty面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

RabbitMQ面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Redis面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

Spring Cloud面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

SpringBoot面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

zookeeper面试专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

常见面试算法题汇总专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

计算机网络基础专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南

设计模式专题

这个GItHub上的Java项目开源了,2020最全的Java架构面试复习指南
0ullQ-1625205381307)]

SpringBoot面试专题

[外链图片转存中…(img-jq2MTUHc-1625205381308)]

zookeeper面试专题

[外链图片转存中…(img-B3WM9Ag9-1625205381309)]

常见面试算法题汇总专题

[外链图片转存中…(img-LKlPJkPM-1625205381310)]

计算机网络基础专题

[外链图片转存中…(img-vTsY1vVi-1625205381310)]

设计模式专题

[外链图片转存中…(img-xzO9715S-1625205381311)]

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

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

相关文章

计算机网络tcp三次握手,快速掌握_计算机网络_TCP_三次握手

虽然这个话题已经是老生常谈了&#xff0c;随手一搜资料一堆&#xff0c;但是让人快速掌握&#xff0c;我认为应该有几个概念先被明确指出&#xff0c;再放出那张大同小异的时序图。01关注的字段探讨三次握手问题前&#xff0c;不得不先了解TCP报文段中存在的这四个位置&#x…

Java高级工程师每日面试题精选,面试经历分享

MySQL为何不选择平衡二叉树 既然平衡二叉树解决了普通二叉树的问题&#xff0c;那么mysql为何不选择平衡二叉树作为索引呢? 索引需要存储什么 让我们想一想&#xff0c;如果我们要把索引存起来&#xff0c;那么应该存哪些信息呢&#xff0c;它应该存储三块信息&#xff1a;…

Java面试题目,java关键字final

1 进程 进程与程序 操作系统之中最为通用的概念就是「进程」。与此相关的面试题以及各种技术优化策略也层出不穷&#xff0c;足以够证明它对于理解操作系统中举足轻重的地位。事实上&#xff0c;通过「进程」&#xff0c;程序员可以更为直观的理解自己所开发的软件&#xff0…

工作组无法访问计算机用户,工作组计算机无法访问,详细教您工作组计算机无法访问怎么解决...

电脑用户反映称在局域网中&#xff0c;查看工作组计算机时说无法访问&#xff0c;没有权限使用网络资源。就是双击“查看工作组计算机”时&#xff0c;提示“Workgroup无法访问。” what the fuck &#xff01;&#xff01;怎么解决&#xff1f;(泄气)下面&#xff0c;小编给大…

Java面试题目,java工程师成神之路

2. ZooKeeper 介绍 2.1. ZooKeeper 由来 正式介绍 ZooKeeper 之前&#xff0c;我们先来看看 ZooKeeper 的由来&#xff0c;还挺有意思的。 下面这段内容摘自《从 Paxos 到 ZooKeeper 》第四章第一节&#xff0c;推荐大家阅读一下&#xff1a; ZooKeeper 最早起源于雅虎研究院…

Java面试题目,极客时间免费课程

一、对Kafka的认识 1.Kafka的基本概念 2.安装与配置 3.生产与消费 4.服务端参数配置 二、生产者 1.客户端开发 2.原理分析 3.重要的生产者参数 三、消费者 1.消费者与消费组 2.客户端开发 四、主题与分区 1.主题的管理 2.初识KafkaAdminCilent 3.分区的管理 4.如何…

w7重启计算机打印机无法使用,win7系统电脑重启打印机服务就会被关闭的解决方法...

很多小伙伴都遇到过win7系统电脑重启打印机服务就会被关闭的困惑吧&#xff0c;一些朋友看过网上零散的win7系统电脑重启打印机服务就会被关闭的处理方法&#xff0c;并没有完完全全明白win7系统电脑重启打印机服务就会被关闭是如何解决的&#xff0c;今天小编准备了简单的解决…

Java面试题!centos安装yum

技术焦虑 现在的技术圈子很火热&#xff0c;任何技术点&#xff0c;任何知识&#xff0c;只要你肯搜索&#xff0c;都能找到资料。但是现在技术圈确实有一个不好的地方&#xff0c;就是贩卖焦虑。这种贩卖焦虑的点并不在于形式&#xff0c;而是一种普遍的心态。特别是对于那种…

2016年全国计算机技术与软件,2016年的上半年的全国计算机技术与软件专业技术资格(水平)考.doc...

2016年的上半年的全国计算机技术与软件专业技术资格(水平)考.doc (1页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;19.90 积分&#xfeff;2011年上半年全国计算机技术与软件专业技术资格(水平)考试…

Java面试题!java面向对象程序设计答案

一、对Kafka的认识 1.Kafka的基本概念 2.安装与配置 3.生产与消费 4.服务端参数配置 二、生产者 1.客户端开发 必要的参数配置消息的发送序列化分区器生产者拦截器 2.原理分析 整体架构元数据的更新 3.重要的生产者参数 三、消费者 1.消费者与消费组 2.客户端开发 必要的…

Java面试题,java培训北京哪家好

一、公务员都不要35岁以上的&#xff0c;何况大公司 这让很多人感到惶恐&#xff0c;现在职场上有一种现象&#xff1a;很多用人单位会在招聘信息上明确标注&#xff0c;年龄需在35岁以下。为什么有经验、有人脉的职场中年人会如此遭“嫌弃”呢&#xff1f; 首先&#xff0c;…

Java面试题,java工程师求职简历

One&#xff1a;JVM实践思维图&#xff08;完整版&#xff09; Two&#xff1a; 走近Java 概述 Java技术体系Java发展史Java虚拟机家族&#xff1a;&#xff08;Sun Classic/Exact VM、HotSpot VM、Mobile/Embedded VM、BEA JRockit/IBM J9 VM、BEA Liquid VM/Azul VM、Apache…

java高分面试指南:javamvc模式简单案例

Spring面试高频问题 SpringMVC面试高频问题 MyBatis面试高频问题 SpringBoot面试高频题 SpringCloud面试高频问题 Redis高级面试题 Dubbo高频常问面试问题 Java虚拟机&#xff08;JVM&#xff09; MySQL数据库高频面试问题 Java高频面试专题合集解析&#xff1a; 当然在这还有更…

java高分面试指南:java单例模式双重检查

1. CAP 的由来 要理解 CAP&#xff0c;首先我们要清楚&#xff0c;为何会有人提出 CAP&#xff1f;他提出 CAP 是为了解决什么问题&#xff1f; 时间回到 1985 年&#xff0c;彼时&#xff0c;后来证明了 CAP 理论的 Lynch 教授此时给当时的 IT 界来了一记惊雷&#xff1a; …

win10计算机磁盘图标,Win10 21H1怎么更换电脑磁盘的图标标识

导语&#xff1a;每台win10电脑的磁盘图标都是一样的,有什么办法可以修改硬盘图标呢?为了让我们的电脑更具个性化,小编给大家分享下Win10 21H1怎么更换电脑磁盘的图标标识。方法如下&#xff1a;手动配置.inf文件1、首先&#xff0c;将要设置为驱动器图标的图标文件(ico格式)复…

java高分面试指南:java定时删除文件

本文框架如下 第一部分&#xff0c;主要是在阅读代码过程中的日志和笔记&#xff1b; 第二部分&#xff0c;主要介绍了 Redis 的主要框架&#xff0c;以及 Redis 是如何提供服务的&#xff0c;从一个最简单的命令开始讲起&#xff1b; 第三部分&#xff0c;主要介绍 Redis 底…

大牛手把手教你!2021大厂Java面试经历

我听到的一些发声 你们赚的钱已经可以了&#xff1a; 我一个发小是做土木工程的&#xff0c;上海大学博士&#xff0c;参与很多著名建筑的工程&#xff0c;但是从薪资上看&#xff0c;还不如一些稍微像样的公司的6年多的高级开发。为什么&#xff1f;这就是行业的红利&#xf…

登录华为账户显示无法连接服务器,App提示连接不到服务器

App提示连接不到服务器 内容精选换一换本章节指导您使用MongoDB客户端&#xff0c;通过弹性云服务器内网方式连接GaussDB(for Mongo)集群实例。操作系统使用场景&#xff1a;弹性云服务器的操作系统以Linux为例&#xff0c;客户端本地使用的计算机系统以Windows为例。目标实例必…

大牛深入讲解!9次Java面试经验总结

阿里巴巴Java岗面试题分享 1.HashMap 的内部结构&#xff1f;内部原理&#xff1f;和 HashTable 的区别&#xff0c;假如发⽣了 hash 碰撞&#xff0c;如何设计能让遍历效率⾼&#xff1f; 2.讲一讲讲讲 ConcurrentHashMap吧。 3.讲一下JVM虚拟机内存结构&#xff0c;以及它…

大牛深入讲解!最经典的HashMap图文详解

栈和队列部分&#xff08;10&#xff09; 设计一个有getMin功能的栈&#xff08;士★☆☆☆&#xff09; 由两个栈组成的队列&#xff08;尉★★☆☆&#xff09; 如何仅用递归函数和栈操作逆序一个栈&#xff08;尉★★☆☆&#xff09; 猫狗队列&#xff08;士★☆☆☆&am…