Java避免死锁的几个常见方法(有测试代码和分析过程)
目录
Java避免死锁的几个常见方法
死锁产生的条件
上死锁代码
然后 :jstack 14320 >> jstack.text
Java避免死锁的几个常见方法
Java避免死锁的几个常见方法
- 避免一个线程同时获取多个锁。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
死锁产生的条件
- 互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
- 请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
- 不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
- 环路等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链死锁问题
上死锁代码
package cn.net.cdsz.ccb.test;public class TestDeadLock {private static Object obj1 = new Object();private static Object obj2 = new Object();public static void main(String[] args) {new Thread(new Thread1()).start();new Thread(new Thread2()).start();}private static class Thread1 implements Runnable {@Overridepublic void run() {synchronized (obj1) {System.out.println("Thread1 拿到 obj1 的锁");try {//停顿2秒的意义在于,让thread2线程拿到obj2的锁Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj2) {System.out.println("Thread1 拿到 obj2 的锁");}}}}private static class Thread2 implements Runnable {@Overridepublic void run() {synchronized (obj2) {System.out.println("Thread2 拿到 obj2 的锁");try {//停顿2秒的意义在于,让thread1线程拿到obj1的锁Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (obj1) {System.out.println("Thread2 拿到 obj1 的锁");}}}}}

一直等待下了。。。

去找pid:14320
然后 :jstack 14320 >> jstack.text
得到以下内容:
2023-04-14 14:51:33
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.31-b07 mixed mode):"JMX server connection timeout 21" #21 daemon prio=5 os_prio=0 tid=0x000000002167d800 nid=0x6108 in Object.wait() [0x00000000225ef000]java.lang.Thread.State: TIMED_WAITING (on object monitor)at java.lang.Object.wait(Native Method)at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)- locked <0x000000076e3b32b8> (a [I)at java.lang.Thread.run(Thread.java:745)"RMI Scheduler(0)" #20 daemon prio=5 os_prio=0 tid=0x0000000021674800 nid=0x3d78 waiting on condition [0x00000000224ee000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x000000076dc34d08> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)"RMI TCP Connection(1)-192.168.136.113" #19 daemon prio=5 os_prio=0 tid=0x0000000021a3b800 nid=0x10c0 runnable [0x00000000223ee000]java.lang.Thread.State: RUNNABLEat java.net.SocketInputStream.socketRead0(Native Method)at java.net.SocketInputStream.read(SocketInputStream.java:150)at java.net.SocketInputStream.read(SocketInputStream.java:121)at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)at java.io.BufferedInputStream.read(BufferedInputStream.java:265)- locked <0x000000076e281978> (a java.io.BufferedInputStream)at java.io.FilterInputStream.read(FilterInputStream.java:83)at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:550)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$240(TCPTransport.java:683)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1/410101441.run(Unknown Source)at java.security.AccessController.doPrivileged(Native Method)at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at java.lang.Thread.run(Thread.java:745)"RMI TCP Accept-0" #18 daemon prio=5 os_prio=0 tid=0x00000000212dc000 nid=0x8584 runnable [0x000000000153e000]java.lang.Thread.State: RUNNABLEat java.net.DualStackPlainSocketImpl.accept0(Native Method)at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:404)at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)- locked <0x000000076dc69d98> (a java.net.SocksSocketImpl)at java.net.ServerSocket.implAccept(ServerSocket.java:545)at java.net.ServerSocket.accept(ServerSocket.java:513)at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:400)at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:372)at java.lang.Thread.run(Thread.java:745)"DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x000000000365b000 nid=0xae0 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Thread-1" #15 prio=5 os_prio=0 tid=0x000000001ec17000 nid=0x69ac waiting for monitor entry [0x0000000020a1f000]java.lang.Thread.State: BLOCKED (on object monitor)at cn.net.cdsz.ccb.test.TestDeadLock$Thread2.run(TestDeadLock.java:46)- waiting to lock <0x000000076c88add0> (a java.lang.Object)- locked <0x000000076c88ade0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)"Thread-0" #14 prio=5 os_prio=0 tid=0x000000001ec24800 nid=0x8d08 waiting for monitor entry [0x000000002091f000]java.lang.Thread.State: BLOCKED (on object monitor)at cn.net.cdsz.ccb.test.TestDeadLock$Thread1.run(TestDeadLock.java:26)- waiting to lock <0x000000076c88ade0> (a java.lang.Object)- locked <0x000000076c88add0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)"Service Thread" #13 daemon prio=9 os_prio=0 tid=0x000000001eb16000 nid=0x8ac8 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C1 CompilerThread3" #12 daemon prio=9 os_prio=2 tid=0x000000001ea92800 nid=0x67b4 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread2" #11 daemon prio=9 os_prio=2 tid=0x000000001ea8f800 nid=0x5c68 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread1" #10 daemon prio=9 os_prio=2 tid=0x000000001ea8f000 nid=0x6b4c waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"C2 CompilerThread0" #9 daemon prio=9 os_prio=2 tid=0x000000001ea8d800 nid=0x7974 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"JDWP Command Reader" #8 daemon prio=10 os_prio=0 tid=0x000000001ea53800 nid=0x3634 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"JDWP Event Helper Thread" #7 daemon prio=10 os_prio=0 tid=0x000000001ea4d800 nid=0x86e0 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"JDWP Transport Listener: dt_socket" #6 daemon prio=10 os_prio=0 tid=0x000000001ea41000 nid=0x540 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001e9e6000 nid=0x83a0 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001e9e5000 nid=0x8dec runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001d2eb800 nid=0x8670 in Object.wait() [0x000000001fd1f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000076c3862f8> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)- locked <0x000000076c3862f8> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:158)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001d2ea000 nid=0x8ba4 in Object.wait() [0x000000001fc1e000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x000000076c385d68> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)- locked <0x000000076c385d68> (a java.lang.ref.Reference$Lock)"VM Thread" os_prio=2 tid=0x000000001e9a1800 nid=0x6398 runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000003670000 nid=0x7e64 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000003671800 nid=0x8218 runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000003673000 nid=0x7830 runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000003674800 nid=0x8e8c runnable "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000003676800 nid=0x8114 runnable "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000003678000 nid=0x8220 runnable "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x000000000367b000 nid=0x6fc0 runnable "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x000000000367c000 nid=0x26d8 runnable "GC task thread#8 (ParallelGC)" os_prio=0 tid=0x000000000367d800 nid=0x8238 runnable "GC task thread#9 (ParallelGC)" os_prio=0 tid=0x000000000367e800 nid=0x82a4 runnable "VM Periodic Task Thread" os_prio=2 tid=0x000000001eb18000 nid=0x8900 waiting on condition JNI global references: 4894Found one Java-level deadlock:
=============================
"Thread-1":waiting to lock monitor 0x000000001d2f21b8 (object 0x000000076c88add0, a java.lang.Object),which is held by "Thread-0"
"Thread-0":waiting to lock monitor 0x000000001d2ef668 (object 0x000000076c88ade0, a java.lang.Object),which is held by "Thread-1"Java stack information for the threads listed above:
===================================================
"Thread-1":at cn.net.cdsz.ccb.test.TestDeadLock$Thread2.run(TestDeadLock.java:46)- waiting to lock <0x000000076c88add0> (a java.lang.Object)- locked <0x000000076c88ade0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)
"Thread-0":at cn.net.cdsz.ccb.test.TestDeadLock$Thread1.run(TestDeadLock.java:26)- waiting to lock <0x000000076c88ade0> (a java.lang.Object)- locked <0x000000076c88add0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)Found 1 deadlock.
以上jstack.text内容的最后:

可以清晰的看到:
Thread-1获取了 <0x000000076c88ade0> 的锁,等待获取 <0x000000076c88add0> 这个锁
Thread-0获取了 <0x000000076c88add0> 的锁,等待获取 <0x000000076c88ade0> 这个锁
由此可见,发生了死锁。
避免死锁的几个常见方法
- 避免一个线程同时获取多个锁。
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
- 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
参考:【JVM】面试题之死锁及问题是怎么定位_jvm线程锁定定位_it噩梦的博客-CSDN博客
相关文章:
Java避免死锁的几个常见方法(有测试代码和分析过程)
目录 Java避免死锁的几个常见方法 死锁产生的条件 上死锁代码 然后 :jstack 14320 >> jstack.text Java避免死锁的几个常见方法 Java避免死锁的几个常见方法 避免一个线程同时获取多个锁。避免一个线程在锁内同时占用多个资源,尽量保证每个锁…...
go binary包
binary包使用与详解 最近在看一个第三方包的库源码,bigcache,发现其中用到了binary 里面的函数,所以准备研究一下。 可以看到binary 包位于encoding/binary,也就是表示这个包的作用是编辑码作用的,看到文档给出的解释…...
CompletableFuture使用详解(IT枫斗者)
CompletableFuture使用详解 简介 概述 CompletableFuture是对Future的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,同时CompletableFuture实现了对任务编排的能力。借助这项能力…...
4.15--设计模式之创建型之责任链模式(总复习版本)---脚踏实地,一步一个脚印
一、什么是责任链模式: 责任链模式属于行为型模式,是为请求创建了一个接收者对象的链,将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。 当一个请求从链式的首端发出时&a…...
STM32+W5500实现以太网通信
STM32系列32位微控制器基于Arm Cortex-M处理器,旨在为MCU用户提供新的开发自由度。它包括一系列产品,集高性能、实时功能、数字信号处理、低功耗/低电压操作、连接性等特性于一身,同时还保持了集成度高和易于开发的特点。本例采用STM32作为MC…...
全网最详细,Jmeter性能测试-性能基础详解,终成测试卷王(一)
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 发起请求 发起HTTP…...
人工智能概述
一、人工智能发展必备三要素 算法 数据 算力 CPU、GPU、TPU 计算力之CPU、GPU对比: CPU主要适合I\O密集型任务GPU主要适合计算密集型任务 什么样的程序适合在GPU上运行? 计算密集型的程序 所谓计算密集型(Compute-intensive)的程序,就是…...
API接口安全—webservice、Swagger、WEBpack
API接口安全—webservice、Swagger、WEBpack1. API接口介绍1.1. 常用的API接口类1.1.1. API接口分类1.1.1.1. 类库型API1.1.1.2. 操作系统型API1.1.1.3. 远程应用型API1.1.1.4. WEB应用型API1.1.1.5. 总结1.1.2. API接口类型1.1.2.1. HTTP类接口1.1.2.2. RPC类接口1.1.2.3. web…...
从前M个字母中取N个的无重复排列 [2*+]
目录 从前M个字母中取N个的无重复排列 [2*+] 程序设计 程序分析 从前M个字母中取N个的无重复排列 [2*+] 输出从前M个字母中取N个的无重复字母排列 Input 输入M N 1<=M=10, N<=M Output 按字典序输出排列 Sample Input 4 2 Sample Output A B A C A D B A B C B …...
ES forceMerge 强制段合并为什么会提升检索性能?
根据以前的测试,forceMerge段合并,将段的个数合并成一个。带来了将近一倍的性能提升,测试过程文档(请参考我的另外一篇文章):ES优化实战- forceMerge搜索提升测试报告_es forcemerge_水的精神的博客-CSDN博…...
macOS Ventura 13.3.1 (22E261) Boot ISO 原版可引导镜像
本站下载的 macOS 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也支持在 Windows 和 Linux 中创建可引导介质。 macOS Ventura 13.3.1 为 Mac 提供下…...
html+css+JavaScript+json+servlet的社区系统(手把手教学)
目录 课前导读: 一、系统前期准备 二、前端代码的编写 三、登陆页面简介 四、注册页面 五、社区列表页 六、社区详情页 七、社区发帖页 八、注销 九、访问链接 登陆页面http://175.178.20.77:8080/java106_blog_system/login.html 总结: 课前…...
UI Toolkit(1)
UI ToolkitUI Toolkit界面画布设置背景制作UI布局UI Toolkit界面 在Unity 2021LTS版本之后UI Toolkit也被内置在Unity中,Unity有意的想让UI Toolkit 成为UI的主要搭建方式,当然与UGUI相比还是有一定的差别。他们各有有点,这次我们就开始介绍…...
vLive带你走进虚拟直播世界
虚拟直播是什么? 虚拟直播是基于5G实时渲染技术,在绿幕环境下拍摄画面,通过实时抠像、渲染与合成,再推流到直播平台的一种直播技术。尽管这种技术早已被影视工业所采用,但在全民化进程中却是困难重重,面临…...
初谈 ChatGPT
引子 最近,小编发现互联网中的大 V 突然都在用 ChatGPT 做宣传:“ChatGPT不会淘汰你,能驾驭ChatGPT的人会淘汰你”、“带领一小部分人先驾驭ChatGPT”。 确实,ChatGPT这个新生事物,如今被视为蒸汽机、电脑、iPhone 般的…...
JAVA练习103-螺旋矩阵
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 提示:这里可以添加本文要记录的大概内容: 4月9日练习内容 提示:以下是本篇文章正文内容,下面案例可供参考 一、题目-螺…...
RecvByteBufAllocator内存分配计算
虽然了解了整个内存池管理的细节,包括它的内存分配的具体逻辑,但是每次从NioSocketChannel中读取数据时,应该分配多少内存去读呢? 例如,客户端发送的数据为1KB , 应该分配多少内存去读呢? 例如:…...
图数据结构与算法
什么是图数据的结构 图是由顶点和边组成的非线性数据结构。顶点有时也称为节点,边是连接图中任意两个节点的线或弧。更正式地说,图由一组顶点 ( V ) 和一组边 ( E ) 组成。该图由 G(E, V) 表示。 图的组成部分 顶点:顶点是图的基本单位。有时,顶点也称为顶点或节点。每个节…...
科普:c语言与C++的区别
C语言和C语言是两种广泛使用的编程语言,尽管它们非常相似,但它们在某些方面也存在不同之处。本文将详细介绍C语言和C语言的区别。 1. 编程范式 C语言是一种过程式编程语言,它的设计目标是为了编写操作系统和其他系统级编程。C语言是一种面向…...
流量整形(GTS和LR)
Generic Traffic Shaping通用流量整形 通用流量整形(简称GTS)可以对不规则或不符合预定流量特性的流量进行整形,以保证网络上下游之间的带宽匹配,避免拥塞发生。 GTS与CAR一样,都采用了令牌桶技术来控制流量。GTS与CAR的主要区别在于:利用CAR进行报文流量控制时,…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
