当前位置: 首页 > news >正文

ArrayList源码分析

ArrayList源码分析

  • 目标:
  • 一、 ArrayList的简介
  • 二、ArrayList原理分析
    • 2.1 ArrayList的数据结构源码分析
    • 2.2 ArrayList默认容量&最大容量
    • 2.3 为什么ArrayList查询快,增删慢?
    • 2.4 ArrayList初始化容量
      • 1、创建ArrayList对象分析:无参数
      • 2、创建ArrayList对象分析:带有初始化容量构造方法
    • 2.5 ArrayList扩容原理
  • 三、ArrayList线程安全问题及解决方案
    • 3.1 错误复现
    • 3.2 导致ArrayList线程不安全的源码分析
    • 3.3 解决方案
  • 四、ArrayList的Fail-Fast机制深入理解

目标:

  • 理解ArrayList的底层数据结构
  • 深入掌握ArrayList查询快,增删慢的原因
  • 掌握ArrayList的扩容机制
  • 掌握ArrayList初始化容量过程
  • 掌握ArrayList出现线程安全问题原因及解决方案
  • 掌握ArrayList的Fail-Fast机制

一、 ArrayList的简介

在这里插入图片描述

ArrayList集合是CollectionList接口的实现类。底层的数据结构是数组。数据结构特点 : 增删慢,查询快。线程不安全的集合!
许多程序员开发的时候,使用集合基本上无脑选取ArrayList!不建议这种用法。
ArrayList的特点:

  • 单列集合 : 对应与Map集合来说【双列集合】
  • 有序性 : 存入的元素和取出的元素是顺序是一样的
  • 元素可以重复 : 可以存入两个相同的元素
  • 含带索引的方法 : 数组与生俱来含有索引【下角标】

二、ArrayList原理分析

2.1 ArrayList的数据结构源码分析

//空的对象数组
private static final Object[] EMPTY_ELEMENTDATA = {}; 
//默认容量空对象数组,通过空的构造参数生成ArrayList对象实例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 
//ArrayList对象的实际对象数组!
transient Object[] elementData; // non-private to simplify nested class access
//1、为什么是Object类型呢?利用面向对象的多态特性,当前ArrayList的可以存储任意引用数据类型。
//2、ArrayList有一个问题,不能存储基本数据类型!就是数组的类型是Object类型

2.2 ArrayList默认容量&最大容量

//默认的初始化容量是10
private static final int DEFAULT_CAPACITY = 10; 
//最大容量    : 2^31 - 1 - 8 = 21 4748 3639【21亿】
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

为什么最大容量要-8呢?
目的是为了存储ArrayList集合的基本信息,比如list集合的最大容量!
在这里插入图片描述

2.3 为什么ArrayList查询快,增删慢?

ArrayList的底层数据结构就是一个Object数组一个可变的数组,对于其的所有操作都是通过数组来实 现的。

  • 数组是一种,查询快、增删慢!
  • 查询数据是通过索引定位,查询任意数据耗时均相同。查询效率贼高!
  • 删除数据时,要将原始数据删除,同时后面的每个数据迁移。删除效率就比较低
  • 新增数据,在添加数组的位置加入数组,同时在数组后面位置后移以为!添加效率极低!

在这里插入图片描述

2.4 ArrayList初始化容量

ArrayList底层是数组,动态数组!

  • 底层是Object对象数组,数组存储的数据类型是Object,数组名字为elementData。
 transient Object[] elementData; // non-private to simplify nested class access

1、创建ArrayList对象分析:无参数

创建ArrayList的之后,ArrayList容量是多少呢?回答10是错误的!回答0是正确【限定条件,在
JDK1.8中】
如何 初始化 动态数组的容量?10个

构造方法

/*** Constructs an empty list with an initial capacity of ten. */
//空参构造时,创建一个空数组 
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 
}
//空数组!
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

在执行add()方法的时候初始化!【懒加载】
判断当前数组的容量是否有存储空间,如果没有初始化一个10的容量。

//向数组中,添加一个元素 
public boolean add(E e) {//确保有容量,如果第一次添加,会初始化一个容量为10的list //size当前集合元素的个数,随着添加的元素递增ensureCapacityInternal(size + 1);  // Increments modCount!! //添加元素elementData[size++] = e; return true;
}
//ensureCapacityInternal确保有容量,如果第一次添加,会初始化一个容量为10的list 
private void ensureCapacityInternal(int minCapacity) {//两个方法ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); 
}
// calculateCapacity(elementData, minCapacity) 拿着当前ArrayList的数组,与当前数组中的元素个数。计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) 
{//ArrayList的数组与默认的数组进行比较。 //{}  == {}if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {/true //DEFAULT_CAPACITY = 10//minCapacity 1 //1和10比谁大 10return Math.max(DEFAULT_CAPACITY, minCapacity);//计算之后,返回的初始化容量是10}return minCapacity; 
}
// ensureExplicitCapacity() 确保不会超过数组的真实容量 
private void ensureExplicitCapacity(int minCapacity) { //minCapacity 当前计算后容量    10modCount++;//对当前数组操作计数器 // overflow-conscious code//最小的容量: 10 - 当前数组的容量{} 0if (minCapacity - elementData.length > 0) grow(minCapacity);//做了扩容
}

2、创建ArrayList对象分析:带有初始化容量构造方法

//创建ArrayList集合,并且设置固定的集合容量 
public ArrayList(int initialCapacity) { //initialCapacity 手动设置的初始化容量if (initialCapacity > 0) {//判断容量是否大于0,如果大于0 //创建一个对象数组位指定容量大小,并且交给ArrayList对象 this.elementData = new Object[initialCapacity]; //如果设置的容量为0,设置默认数组} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;//默认的元素数据数组{} } else {//如果不是0,也不是大于0的数,会抛出非法参数异常!throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);} 
}

注意 : 使用ArrayList的集合,建议如果知道集合的大小,最好提前设置。提示集合的使用效率!

2.5 ArrayList扩容原理

add方法先要确保数组的容量足够,防止数组已经填满还往里面添加数据造成数组越界:

  1. 如果数组空间足够,直接将数据添加到数组中
  2. 如果数组空间不够了,则进行扩容。扩容1.5倍扩容。
  3. 扩容 : 原始数组copy新数组中,同时向新数组后面加入数据

注意 : new的ArrayList的对象没有容量的,在第一次添加的add,会进行第一次扩容。0 -> 10!

//grow扩容数组
private void grow(int minCapacity) {//minCapacity 当前数组的最小容量,存储了多少个元素 // overflow-conscious code//获取当前存储数据数组的长度int oldCapacity = elementData.length;//新的容量 = 旧的容量 + 扩容的容量【旧容量/2 = 0.5旧容量】 //扩容1.5倍扩容int newCapacity = oldCapacity + (oldCapacity >> 1); //极端情况过滤 : 新的容量 - 旧的容量小于0【int值移除】 if (newCapacity - minCapacity < 0)newCapacity = minCapacity;//不扩容了 //新的容量,比ArrayList的最大值,还要大if (newCapacity - MAX_ARRAY_SIZE > 0)//设置新的容量为ArrayList的最大值,以ArrayList最大值为当前容量 newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);
}

总结:

  1. 扩容的规则并不是翻倍,是原来容量的1.5倍
  2. ArrayList的数组最大值Integer.MAX_VALUE。不允许超过这个最大值
  3. 新增元素时,没有严格的数据值的检查。所有可用设置null

三、ArrayList线程安全问题及解决方案

3.1 错误复现

ArrayList 我们都知道底层是以数组方式实现的,实现了可变大小的数组,它允许所有元素,包括null。
看下面一个例子:开启多个线程操作List集合,向ArrayList中增加元素,同时去除元素

  //全局线程共享集合ArrayListprotected static ArrayList<Object> arrayList = new ArrayList<>();@Testvoid arrayListTest() {//1.创建线程数组【500】Thread[] threads = new Thread[500];//2.遍历数组,向线程中添加500个线程对象for (int i = 0; i < threads.length; i++) {threads[i] = new MyThread();threads[i].start();//启动线程}//3.遍历线程,等待线程执行完毕【等待所有线程执行完毕】for (int i = 0; i < threads.length; i++) {try {threads[i].join();//等待线程执行完毕} catch (InterruptedException e) {e.printStackTrace();}}//线程执行内容 : 向集合中添加自己的线程名称//4.遍历list集合,获取所有线程的名称for (Object threadName : arrayList) {System.out.println("threadName = " + threadName);}}//线程执行内容,是想集合中添加自己的线程名称class MyThread extends Thread {@Overridepublic void run() {try {//线程休眠1000Thread.sleep(1000);//向集合中添加自己的线程名称【操作共享内容,会出现线程安全问题】arrayList.add(Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}}

运行代码结果可知,会出现以下几种情况:

  • ①打印null
  • ②某些线程并未打印
  • ③数组角标越界异常

在这里插入图片描述

3.2 导致ArrayList线程不安全的源码分析

ArrayList成员变量

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable 
{//ArrayList的Object的数组存所有元素。transient Object[] elementData; // non-private to simplify nested class 
access//size变量保存当前数组中元素个数。 private int size;
//...
}
  • ArrayList的Object的数组存储所有元素。
  • size变量保存当前数组中元素个数。

出现线程不安全源码之一 : add()方法

public boolean add(E e) {//确保有容量,如果第一次添加,会初始化一个容量为10的list //size当前集合元素的个数,随着添加的元素递增ensureCapacityInternal(size + 1);  // Increments modCount!! //添加元素elementData[size++] = e; return true;
}

add添加元素,实际做了两个大的步骤:

  1. 判断elementData数组容量是否满足需求
  2. 在elementData对应位置上设置值

线程不安全的隐患【1】,导致③数组下标越界异常
在这里插入图片描述
线程不安全的隐患【2】,导致①Null、②某些线程并未打印
致①Null、②某些线程并未打印深层次原因是因为多线程情况下出现了指令重排和不保证原子性问题。详见Volatile关键字在这里插入图片描述
由此我们可以得出,在多线程情况下操作ArrayList 并不是线性安全的。

3.3 解决方案

第一种方案:使用Vector集合,Vector集合是线程安全的

//线程安全问题解决方案1
protected static Vector<Object> vector = new Vector<>();

第二种方案:使用Collections.synchronizedList。它会自动将我们的list方法进行改变,最后返回给我们加锁了List

//线程安全问题解决方案2 
//将集合改为同步集合
protected static List<Object> synList = Collections.synchronizedList(arrayList);

第三种方案:使用JUC中的CopyOnWriteArrayList类进行替换。

//线程安全问题解决方案3 JUC 【最佳选择】
protected static CopyOnWriteArrayList<Object> copyOnWriteArrayList = new 
CopyOnWriteArrayList<>();

因为CopyOnWriteArrayList中的add操作使用了lock锁保证了原子性同时保证线程安全,而且数组也使用了volatile关键字,保证可见性和防止指令重排

在这里插入图片描述
在这里插入图片描述

四、ArrayList的Fail-Fast机制深入理解

什么是Fail-Fast机制?
"快速失败"即Fail-Fast机制,它是Java中一种错误检测机制!
当多钱程对集合进行结构上的改变,或者在迭代元素时直接调用自身方法改变集合结构而没有通知迭代器时,有可能会触发Fail-Fast机制并抛出异常【ConcurrentModificationException】。注意,是有可能
触发Fail-Fast,而不是肯定!

触发时机 : 在迭代过程中,集合的结构发生改变,而此时迭代器并不知情,或者还没来得及反应,便会
产生Fail-Fast事件。

再次强调,迭代器的快速失败行为无法得到保证!一般来说,不可能对是否出现不同步并发修改,或者
自身修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。

Java.util包中的所有集合类都是快速失败的,而java.util.concurrent包中的集合类都是安全失败的;快
速失败的迭代器抛出ConcurrentModificationException,而安全失败的迭代器从不抛出这个异常。

ArrayList的Fast-Fail事件复现及解决方案

    /*** 目标: 复现Fast_Fail机制* 1.产生条件 :*  当多线程操作同一个集合*  同时遍历这个集合,该集合被修改!* 2.解决方案 :使用并发编程包中的集合,CopyOnWriteArrayList替换原有ArrayList集合。*///定义全局共享集合  :static ArrayList<String> list = new ArrayList<>();//Fast_Fail机制CopyOnWriteArrayList//    static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();@Testvoid arrayListTest() {//创建线程1,并且向集合添加元素,打印集合中的内容Thread thread1 = new Thread(() -> {//并且向集合添加元素for (int i = 0; i < 6; i++) {list.add("" + i);// 打印集合中的内容printAll();}});thread1.start();//启动线程1//创建线程2,并且向集合添加元素,打印集合中的内容Thread thread2 = new Thread(() -> {//并且向集合添加元素for (int i = 10; i < 16; i++) {list.add("" + i);// 打印集合中的内容printAll();}});thread2.start();//启动线程2}/*** 使用迭代器打印集合*/public static void printAll() {//获取当前集合的迭代器Iterator<String> iterator = list.iterator();//通过迭代器遍历集合while (iterator.hasNext()) {String value = iterator.next();System.out.println(value + ",");}}

使用ArrayList在多线程情况下添加元素时出线ConcurrentModificationException
在这里插入图片描述
解决办法使用并发编程包中的集合,CopyOnWriteArrayList替换原有ArrayList集合。

扩展连接
ArrayList集合底层原理
ArrayList集合特点为什么是增删慢、查询快

相关文章:

ArrayList源码分析

ArrayList源码分析目标:一、 ArrayList的简介二、ArrayList原理分析2.1 ArrayList的数据结构源码分析2.2 ArrayList默认容量&最大容量2.3 为什么ArrayList查询快&#xff0c;增删慢&#xff1f;2.4 ArrayList初始化容量1、创建ArrayList对象分析&#xff1a;无参数2、创建A…...

SpringBoot IOC、DI、@Autowired、@Resource、作用域

一、初识Spring1.1 Spring是什么Spring是一个轻量级Java开发框架&#xff0c;目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个分层的开源框架&#xff0c;为开发Java应用程序提供全面的基础架构支持。Spring负责基础架构&#xff0c;Java开发者可以专…...

链表相关oj题

1.Leetcode203 移除链表元素 解题思路&#xff1a;从头节点开始进行元素删除&#xff0c;每删除一个元素&#xff0c;需要重新链接节点 struct ListNode* removeElements(struct ListNode* head, int val){struct ListNode*dummyheadmalloc(sizeof(struct ListNode));dummyhea…...

【Linux】操作系统(Operator System)

操作系统&#xff08;Operator System &#xff09;一、操作系统的概念二、操作系统的作用三、系统调用和库函数一、操作系统的概念 操作系统是一组控制和管理计算机软硬件资源&#xff0c;为用户提供便捷使用的计算机程序的集合&#xff0c;是配置在计算机硬件系统上的第一层…...

机器学习自学笔记——感知机

感知机预备知识 神经元 ​ 感知机算法最初是由科学家从脑细胞的神经凸起联想而来。如下图&#xff0c;我们拥有三个初始xxx值&#xff0c;x1,x2,x0x_1,x_2,x_0x1​,x2​,x0​。其中x01x_01x0​1为一个初始的常量&#xff0c;专业上称作“偏置”。每个xxx的值都会乘上一个权重…...

C++ Primer第五版_第三章习题答案(21~30)

文章目录练习3.21练习3.22练习3.23练习3.24练习3.25练习3.26练习3.27练习3.28练习3.29练习3.30练习3.21 请使用迭代器重做3.3.3节的第一个练习。 #include <vector> #include <iterator> #include <string> #include <iostream>using std::vector; usi…...

colmap+openmvs进行三维重建流程全记录

window下的colmapopenmvs进行三维重建流程全记录 1.colmap安装与配置 可参考&#xff1a;https://blog.csdn.net/weixin_44153180/article/details/129334018?spm1001.2014.3001.5501 2.openmvs安装与配置 可参考&#xff1a;https://blog.csdn.net/rdw1246010462/article…...

yolov8命令行运行参数详解

序言 整理来自yolov8官方文档常用的一些命令行参数&#xff0c;官方文档YOLOv8 Docs yolov8命令行的统一运行格式为&#xff1a; yolo TASK MODE ARGS其中主要是三部分传参&#xff1a; TASK(可选) 是[detect、segment、classification]中的一个。如果没有显式传递&#xf…...

分布式锁简介

Redis因为单进程、性能高常被用于分布式锁&#xff1b;锁在程序中作用是同步工具&#xff0c;保证共享资源在同一时刻只能被一个线程访问。 Java中经常用的锁synchronized、Lock&#xff0c;但是Java的锁智能保证单机的时候有效&#xff0c;分布式集群环境就无能为力了&#xf…...

【嵌入式Linux学习笔记】Linux驱动开发

Linux系统构建完成后&#xff0c;就可以基于该环境方便地进行开发了&#xff0c;相关的开发流程与MCU类似&#xff0c;但是引入了设备树的概念&#xff0c;编写应用代码要相对复杂一点。但是省去了很多配置工作。 学习视频地址&#xff1a;【正点原子】STM32MP157开发板 字符…...

2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(同步赛)(H题)(线段树)

又到了万物复苏的季节&#xff0c;家乡的苹果树结果了。像往常一样小龙同学被叫回家摘苹果。 假设需要采摘的一棵树上当前有a颗苹果&#xff0c;那么小龙会采摘⌈a/3⌉颗苹果&#xff0c;其中⌈x⌉表示不小于x的最小整数。 但是&#xff0c;为了可持续发展&#xff0c;若a小于1…...

Linux内核Thermal框架详解十三、Thermal Governor(3)

接前一篇文章Linux内核Thermal框架详解十二、Thermal Governor&#xff08;2&#xff09; 二、具体温控策略 上一篇文章介绍并详细分析了bang_bang governor的源码。本文介绍第2种温控策略&#xff1a;fair_share。 2. fair_share fair_share governor总的策略是频率档位⽐较…...

TikTok品牌出海创世纪(二)

目录 1.推荐算法打造王者品牌 2.品牌聚焦海外Z群体 3.持续扩展应用场景 加速品牌全球化传播 品牌聚焦海外Z群体 “这个地球上&#xff0c;三分之二的人都在用Facebook“&#xff0c;这是对Facebook曾经统治地位最直观的描述。 但如今&#xff0c;这家全球社交媒体巨头的光环正…...

iOS中SDK开发 -- cocoapods库创建

在iOS项目中&#xff0c;经常使用cocoadpods来进行依赖管理以及三方库引入等。引入的三方库一般会有几种形式&#xff1a;一、在Pods目录下可以直接看到源代码的开源库&#xff0c;如AFNetworking&#xff0c;Masonry等常见开源库。二、在Pods目录下拉取的项目文件只能看到对应…...

2023年了,还是没学会内卷....

先做个自我介绍&#xff1a;我&#xff0c;普本&#xff0c;通信工程专业&#xff0c;现在飞猪干软件测试&#xff0c;工作时长两年半。 回望疫情纪元&#xff0c;正好是实习 毕业这三年。要说倒霉也是真倒霉&#xff0c;互联网浪潮第三波尾巴也没抓住&#xff0c;狗屁造富神…...

chatGPT爆火,什么时候中国能有自己的“ChatGPT“

目录 引言 一、ChatGPT爆火 二、中国何时能有自己的"ChatGPT" 三、为什么openai可以做出chatGPT? 四、结论 引言 随着人工智能技术的不断发展&#xff0c;自然语言处理技术也逐渐成为了研究的热点之一。其中&#xff0c;ChatGPT作为一项领先的自然语言处理技术…...

【Matlab算法】粒子群算法求解一维非线性函数问题(附MATLAB代码)

MATLAB求解一维非线性函数问题前言正文函数实现&#xff08;可视化处理&#xff09;可视化结果前言 一维非线性函数是指函数的自变量和因变量都是一维实数&#xff0c;而且函数的形式是非线性的&#xff0c;也就是不符合线性函数的形式。在一维非线性函数中&#xff0c;自变量…...

2023 最新发布超全的 Java 面试八股文,整整 1000道面试题,太全了

作为一名优秀的程序员&#xff0c;技术面试都是不可避免的一个环节&#xff0c;一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识。 2023 年的互联网行业竞争越来越严峻&#xff0c;面试也是越来越难&#xff0c;很多粉丝朋友私信希望我出一篇面试专题或…...

产品经理面经|当面试官问你还有什么问题?

相信很多产品经理在跳槽面试的时候&#xff0c;在面试尾声都会遇到这样的环节&#xff0c;面试官会问你有什么问题要问的&#xff0c;一般来说大家都能随时随地甩出几个问题来化解&#xff0c;但其实在这个环节对于应聘者来说也是一个很好的机会来展现自己的能力&#xff0c;甚…...

单链表的基本操作

目录 一.链表的基本概念和结构 二.链表的分类 三.单链表的基本操作 1.创建一个节点 2.打印 3.尾插 4.头插 5.尾删 6.头删 7.查找 8.指定位置插入 9.指定位置删除 10.销毁 一.链表的基本概念和结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

goreplay

1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具&#xff0c;可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长&#xff0c;测试它所需的工作量也会呈指数级增长。GoRepl…...

【题解-洛谷】P10480 可达性统计

题目&#xff1a;P10480 可达性统计 题目描述 给定一张 N N N 个点 M M M 条边的有向无环图&#xff0c;分别统计从每个点出发能够到达的点的数量。 输入格式 第一行两个整数 N , M N,M N,M&#xff0c;接下来 M M M 行每行两个整数 x , y x,y x,y&#xff0c;表示从 …...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术点解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术点解析 第一轮&#xff1a;基础概念问题 请解释Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; 程序员JY回答&#xff1a;Spring框架的核心容器是IoC容器&#xff08;控制反转…...

湖北理元理律师事务所:债务清偿方案中的法律技术革新

文/金融法律研究组 当前债务服务市场存在结构性矛盾&#xff1a;债权人追求快速回款&#xff0c;债务人需要喘息空间。湖北理元理律师事务所通过创新法律技术&#xff0c;在《企业破产法》《民法典》框架下构建梯度清偿模型&#xff0c;实现多方利益平衡。 一、个人债务优化的…...