Java八股文面试题,堪称2026最强!!!

news2026/4/1 6:03:21
1、什么是 java 序列化如何实现 java 序列化 难度系数⭐序列化是一种用来处理对象流的机制所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序 列 化 的 实 现 将 需 要 被 序 列 化 的 类 实 现 Serializable 接 口 该 接 口 没 有 需 要 实 现 的 方 法 implements Serializable 只是为了标注该对象是可被序列化的然后使用一个输出流(如FileOutputStream)来构造一个ObjectOutputStream(对象流)对象接着使用 ObjectOutputStream 对象的 writeObject(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态)要恢复的话则用输入流。2、Http 常见的状态码 难度系数⭐200 OK //客户端请求成功301 Permanently Moved 永久移除)请求的 URL 已移走。Response 中应该包含一个 Location URL, 说明资源现在所处的位置302 Temporarily Moved 临时重定向400 Bad Request //客户端请求有语法错误不能被服务器所理解401 Unauthorized //请求未经授权这个状态代码必须和 WWW-Authenticate 报头域一起使用403 Forbidden //服务器收到请求但是拒绝提供服务404 Not Found //请求资源不存在eg输入了错误的 URL500 Internal Server Error //服务器发生不可预期的错误503 Server Unavailable //服务器当前不能处理客户端的请求一段时间后可能恢复正常3、GET 和POST 的区别 难度系数⭐GET 请求的数据会附在URL 之后就是把数据放置在 HTTP 协议头中以?分割URL 和传输数据参数之间以相连如login.action?namezhagnsanpassword123456。POST 把提交的数据则放置在是 HTTP 包的包体中。GET 方式提交的数据最多只能是 1024 字节理论上POST 没有限制可传较大量的数据。其实这样说是错误的不准确的“GET 方式提交的数据最多只能是 1024 字节因为 GET 是通过 URL 提交数据那么 GET 可提交的数据量就跟URL 的长度有直接关系了。而实际上URL 不存在参数上限的问题HTTP 协议规范没有对 URL 长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE 对URL 长度的限制是2083 字节(2K35)。对于其他浏览器如Netscape、FireFox 等理论上没有长度限制其限制取决于操作系统的支持。POST 的安全性要比GET 的安全性高。注意这里所说的安全性和上面 GET 提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改而这里安全的含义是真正的 Security 的含义比如通过 GET 提交数据用户名和密码将明文出现在 URL 上因为(1)登录页面有可能被浏览器缓存(2)其他人查看浏览器的历史纪录那么别人就可以拿到你的账号和密码了除此之外使用 GET 提交数据还可能会造成 Cross-site request forgery 攻击。Get 是向服务器发索取数据的一种请求而 Post 是向服务器提交数据的一种请求在 FORM表单中Method默认为GET实质上GET 和 POST 只是发送机制不同并不是一个取一个发4、Cookie 和Session 的区别 难度系数⭐Cookie 是 web 服务器发送给浏览器的一块信息浏览器会在本地一个文件中给每个 web 服务器存储 cookie。以后浏览器再给特定的 web 服务器发送请求时同时会发送所有为该服务器存储的 cookieSession 是存储在 web 服务器端的一块信息。session 对象存储特定用户会话所需的属性及配置信息。当用户在应用程序的 Web 页之间跳转时存储在 Session 对象中的变量将不会丢失而是在整个用户会话中一直存在下去Cookie 和session 的不同点无论客户端做怎样的设置session 都能够正常工作。当客户端禁用 cookie 时将无法使用 cookie在存储的数据量方面session 能够存储任意的java 对象cookie 只能存储 String 类 型的对象第二章-Java高级篇1、HashMap底层源码 难度系数⭐⭐⭐HashMap的底层结构在jdk1.7中由数组链表实现在jdk1.8中由数组链表红黑树实现以数组链表的结构为例。JDK1.8之前Put方法JDK1.8之后Put方法篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1hoHashMap基于哈希表的Map接口实现是以key-value存储形式存在即主要用来存放键值对。HashMap 的实现不是同步的这意味着它不是线程安全的。它的key、value都可以为null。此外HashMap中的映射不是有序的。JDK1.8 之前 HashMap 由 数组链表 组成的数组是 HashMap 的主体链表则是主要为了解决哈希冲突(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在的“拉链法”解决冲突.JDK1.8 以后在解决哈希冲突时有了较大的变化当链表长度大于阈值或者红黑树的边界值默认为 8并且当前数组的长度大于64时此时此索引位置上的所有数据改为使用红黑树存储。补充将链表转换成红黑树前会判断即使阈值大于8但是数组长度小于64此时并不会将链表变为红黑树。而是选择进行数组扩容。这样做的目的是因为数组比较小尽量避开红黑树结构这种情况下变为红黑树结构反而会降低效率因为红黑树需要进行左旋右旋变色这些操作来保持平衡 。同时数组长度小于64时搜索时间相对要快些。所以综上所述为了提高性能和减少搜索时间底层在阈值大于8并且数组长度大于64时链表才转换为红黑树。具体可以参考 treeifyBin方法。当然虽然增了红黑树作为底层数据结构结构变得复杂了但是阈值大于8并且数组长度大于64时链表转换为红黑树时效率也变的更高效。2、JVM内存分哪几个区每个区的作用是什么 难度系数⭐⭐java虚拟机 主要分为以下几个区方法区有时候也成为永久代在该区内很少发生垃圾回收但是并不代表不发生GC在这里进行的GC主要是对方法区里的常量池和对类型的卸载方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。该区域是被线程共享的。方法区里有一个运行时常量池用于存放静态编译产生的字面量和符号引用。该常量池具有动态性也就是说常量并不一定是编译时确定运行时生成的常量也会存在这个常量池中。虚拟机栈虚拟机栈也就是我们平常所称的栈内存,它为java方法服务每个方法在执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接和方法出口等信息。虚拟机栈是线程私有的它的生命周期与线程相同。局部变量表里存储的是基本数据类型、returnAddress类型指向一条字节码指令的地址和对象引用这个对象引用有可能是指向对象起始地址的一个指针也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定操作数栈的作用主要用来存储运算结果以及运算的操作数它不同于局部变量表通过索引来访问而是压栈和出栈的方式每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。本地方法栈本地方法栈和虚拟机栈类似只不过本地方法栈为Native方法服务。堆java堆是所有线程所共享的一块内存在虚拟机启动时创建几乎所有的对象实例都在这里创建因此该区域经常发生垃圾回收操作。程序计数器内存空间小字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域。3、Java中垃圾收集的方法有哪些 难度系数⭐采用分区分代回收思想复制算法年轻代中使用的是Minor GC这种GC算法采用的是复制算法(Copying)a) 效率高缺点需要内存容量大比较耗内存b) 使用在占空间比较小、刷新次数多的新生区标记-清除老年代一般是由标记清除或者是标记清除与标记整理的混合实现a) 效率比较低会差生碎片。标记-整理老年代一般是由标记清除或者是标记清除与标记整理的混合实现a) 效率低速度慢需要移动对象但不会产生碎片。4、如何判断一个对象是否存活(或者GC对象的判定方法) 难度系数⭐引用计数法所谓引用计数法就是给每一个对象设置一个引用计数器每当有一个地方引用这个对象时就将计数器加一引用失效时计数器就减一。当一个对象的引用计数器为零时说明此对象没有被引用也就是“死对象”,将会被垃圾回收.引用计数法有一个缺陷就是无法解决循环引用问题也就是说当对象A引用对象B对象B又引用者对象A那么此时A,B对象的引用计数器都不为零也就造成无法完成垃圾回收所以主流的虚拟机都没有采用这种算法。可达性算法(引用链法)该算法的基本思路就是通过一些被称为引用链GC Roots的对象作为起点从这些节点开始向下搜索搜索走过的路径被称为Reference Chain)当一个对象到GC Roots没有任何引用链相连时即从GC Roots节点到该节点不可达则证明该对象是不可用的。在java中可以作为GC Roots的对象有以下几种虚拟机栈中引用的对象、方法区类静态属性引用的对象、方法区常量池引用的对象、本地方法栈JNI引用的对象。5、什么情况下会产生StackOverflowError栈溢出和OutOfMemoryError堆溢出怎么排查 难度系数⭐⭐引发 StackOverFlowError 的常见原因有以下几种无限递归循环调用最常见执行了大量方法导致线程栈空间耗尽方法内声明了海量的局部变量native 代码有栈上分配的逻辑并且要求的内存还不小比如 java.net.SocketInputStream.read0 会在栈上要求分配一个 64KB 的缓存64位 Linux。引发 OutOfMemoryError的常见原因有以下几种内存中加载的数据量过于庞大如一次从数据库取出过多数据集合类中有对对象的引用使用完后未清空使得JVM不能回收代码中存在死循环或循环产生过多重复的对象实体启动参数内存值设定的过小排查可以通过jvisualvm进行内存快照分析栈溢出、堆溢出案例演示public class StackOverFlowTest {private static int count 1;public static void main(String[] args) {//模拟栈溢出//getDieCircle();//模拟堆溢出getOutOfMem();}public static void getDieCircle(){System.out.println(count);getDieCircle();}public static void getOutOfMem(){while (true) {Object o new Object();System.out.println(o);}}}Java6、什么是线程池线程池有哪些创建 难度系数⭐线程池就是事先将多个线程对象放到一个容器中当使用的时候就不用 new 线程而是直接去池中拿线程即可节省了开辟子线程的时间提高的代码执行效率在 JDK 的 java.util.concurrent.Executors 中提供了生成多种线程池的静态方法。ExecutorService newCachedThreadPool Executors.newCachedThreadPool();ExecutorService newFixedThreadPool Executors.newFixedThreadPool(4);ScheduledExecutorService newScheduledThreadPool Executors.newScheduledThreadPool(4);ExecutorService newSingleThreadExecutor Executors.newSingleThreadExecutor();然后调用他们的 execute 方法即可。这4种线程池底层 全部是ThreadPoolExecutor对象的实现阿里规范手册中规定线程池采用ThreadPoolExecutor自定义的实际开发也是。newCachedThreadPool创建一个可缓存线程池如果线程池长度超过处理需要可灵活回收空闲线程若无可回收则新建线程。这种类型的线程池特点是工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。如果长时间没有往线程池中提交任务即如果工作线程空闲了指定的时间(默认为1分钟)则该工作线程将自动终止。终止后如果你又提交了新的任务则线程池重新创建一个工作线程。在使用CachedThreadPool时一定要注意控制任务的数量否则由于大量线程同时运行很有会造成系统瘫痪。newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程如果工作线程数量达到线程池初始的最大数则将提交的任务存入到池队列中。FixedThreadPool是一个典型且优秀的线程池它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是在线程池空闲时即线程池中没有可运行任务时它不会释放工作线程还会占用一定的系统资源。newSingleThreadExecutor创建一个单线程化的Executor即只创建唯一的工作者线程来执行任务它只会用唯一的工作线程来执行任务保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束会有另一个取代它保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务并且在任意给定的时间不会有多个线程是活动的。篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1honewScheduleThreadPool创建一个定长的线程池而且支持定时的以及周期性的任务执行。例如延迟3秒执行。7、为什么要使用线程池 难度系数⭐线程池做的工作主要是控制运行的线程数量处理过程中将任务放入队列然后在线程创建后启动这些任务如果线程数量超过了最 大数量超出数量的线程排队等候等其它线程执行完毕再从队列中取出任务来执行。主要特点:线程复用;控制最大并发数:管理线程。第一:降低资源消耗。通过重复利用己创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时任务可以不需要的等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源如果无限制的创建不仅会消耗系统资源还会降低系统的稳定性使用线程池可以进 行统一的分配调优和监控8、线程池底层工作原理 难度系数⭐第一步线程池刚创建的时候里面没有任何线程等到有任务过来的时候才会创建线程。当然也可以调用 prestartAllCoreThreads() 或者 prestartCoreThread() 方法预创建corePoolSize个线程第二步调用execute()提交一个任务时如果当前的工作线程数corePoolSize直接创建新的线程执行这个任务第三步如果当时工作线程数量corePoolSize会将任务放入任务队列中缓存第四步如果队列已满并且线程池中工作线程的数量maximumPoolSize还是会创建线程执行这个任务第五步如果队列已满并且线程池中的线程已达到maximumPoolSize这个时候会执行拒绝策略JAVA线程池默认的策略是AbortPolicy即抛出RejectedExecutionException异常9、ThreadPoolExecutor对象有哪些参数 怎么设定核心线程数和最大线程数 拒绝策略有哪些 难度系数⭐参数与作用共7个参数corePoolSize核心线程数在ThreadPoolExecutor中有一个与它相关的配置allowCoreThreadTimeOut默认为false当allowCoreThreadTimeOut为false时核心线程会一直存活哪怕是一直空闲着。而当allowCoreThreadTimeOut为true时核心线程空闲时间超过keepAliveTime时会被回收。maximumPoolSize最大线程数线程池能容纳的最大线程数当线程池中的线程达到最大时此时添加任务将会采用拒绝策略默认的拒绝策略是抛出一个运行时错误RejectedExecutionException。值得一提的是当初始化时用的工作队列为LinkedBlockingDeque时这个值将无效。keepAliveTime存活时间当非核心空闲超过这个时间将被回收同时空闲核心线程是否回收受allowCoreThreadTimeOut影响。unitkeepAliveTime的单位。workQueue任务队列常用有三种队列即SynchronousQueue,LinkedBlockingDeque无界队列,ArrayBlockingQueue有界队列。threadFactory线程工厂ThreadFactory是一个接口用来创建worker。通过线程工厂可以对线程的一些属性进行定制。默认直接新建线程。RejectedExecutionHandler拒绝策略也是一个接口只有一个方法当线程池中的资源已经全部使用添加新线程被拒绝时会调用RejectedExecutionHandler的rejectedExecution法。默认是抛出一个运行时异常。线程池大小设置需要分析线程池执行的任务的特性 CPU 密集型还是 IO 密集型每个任务执行的平均时长大概是多少这个任务的执行时长可能还跟任务处理逻辑是否涉及到网络传输以及底层系统资源依赖有关系如果是 CPU 密集型主要是执行计算任务响应时间很快cpu 一直在运行这种任务 cpu的利用率很高那么线程数的配置应该根据 CPU 核心数来决定CPU 核心数最大同时执行线程数加入 CPU 核心数为 4那么服务器最多能同时执行 4 个线程。过多的线程会导致上下文切换反而使得效率降低。那线程池的最大线程数可以配置为 cpu 核心数1 如果是 IO 密集型主要是进行 IO 操作执行 IO 操作的时间较长这是 cpu 出于空闲状态导致 cpu 的利用率不高这种情况下可以增加线程池的大小。这种情况下可以结合线程的等待时长来做判断等待时间越高那么线程数也相对越多。一般可以配置 cpu 核心数的 2 倍。一个公式线程池设定最佳线程数目 线程池设定的线程等待时间线程 CPU 时间/线程 CPU 时间 * CPU 数目这个公式的线程 cpu 时间是预估的程序单个线程在 cpu 上运行的时间通常使用 loadrunner测试大量运行次数求出平均值拒绝策略AbortPolicy直接抛出异常默认策略CallerRunsPolicy用调用者所在的线程来执行任务DiscardOldestPolicy丢弃阻塞队列中靠最前的任务并执行当前任务DiscardPolicy直接丢弃任务当然也可以根据应用场景实现 RejectedExecutionHandler 接口自定义饱和策略如记录日志或持久化存储不能处理的任务10、常见线程安全的并发容器有哪些 难度系数⭐CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMapCopyOnWriteArrayList、CopyOnWriteArraySet采用写时复制实现线程安全ConcurrentHashMap采用分段锁的方式实现线程安全11、Atomic原子类了解多少 原理是什么 难度系数⭐Java 的原子类都存放在并发包 java.util.concurrent.atomic下如下图基本类型使用原子的方式更新基本类型AtomicInteger整型原子类AtomicLong长整型原子类AtomicBoolean布尔型原子类数组类型使用原子的方式更新数组里的某个元素AtomicIntegerArray整形数组原子类AtomicLongArray长整形数组原子类AtomicReferenceArray引用类型数组原子类引用类型AtomicReference引用类型原子类AtomicStampedReference原子更新引用类型里的字段原子类AtomicMarkableReference 原子更新带有标记位的引用类型AtomicIntegerFieldUpdater原子更新整形字段的更新器AtomicLongFieldUpdater原子更新长整形字段的更新器AtomicStampedReference原子更新带有版本号的引用类型。该类将整数值与引用关联起来可用于解决原子的更新数据和数据的版本号以及解决使用 CAS 进行原子更新时可能出现的 ABA 问题AtomicInteger 类利用 CAS (Compare and Swap) volatile native 方法来保证原子操作从而避免 synchronized 的高开销执行效率大为提升。CAS 的原理是拿期望值和原本的值作比较如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是个本地方法这个方法是用来拿“原值”的内存地址返回值是 valueOffset另外value 是一个 volatile 变量因此 JVM 总是可以保证任意时刻的任何线程总能拿到该变量的最新值。12、synchronized底层实现是什么 lock底层是什么 有什么区别 难度系数⭐⭐⭐Synchronized原理方法级的同步是隐式即无需通过字节码指令来控制的它实现在方法调用和返回操作之中。JVM可以从方法常量池中的方法表结构(method_info Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。当方法调用时调用指令将会 检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置如果设置了执行线程将先持有monitor虚拟机规范中用的是管程一词然后再执行方法最后再方法完成(无论是正常完成还是非正常完成)时释放monitor。代码块的同步是利用monitorenter和monitorexit这两个字节码指令。它们分别位于同步代码块的开始和结束位置。当jvm执行到monitorenter指令时当前线程试图获取monitor对象的所有权如果未加锁或者已经被当前线程所持有就把锁的计数器1当执行monitorexit指令时锁计数器-1当锁计数器为0时该锁就被释放了。如果获取monitor对象失败该线程则会进入阻塞状态直到其他线程释放锁。Lock原理Lock的存储结构一个int类型状态值用于锁的状态变更一个双向链表用于存储等待中的线程Lock获取锁的过程本质上是通过CAS来获取状态值修改如果当场没获取到会将该线程放在线程等待链表中。Lock释放锁的过程修改状态值调整等待链表。Lock大量使用CAS自旋。因此根据CAS特性lock建议使用在低锁冲突的情况下。Lock与synchronized的区别Lock的加锁和解锁都是由java代码配合native方法调用操作系统的相关方法实现的而synchronize的加锁和解锁的过程是由JVM管理的当一个线程使用synchronize获取锁时若锁被其他线程占用着那么当前只能被阻塞直到成功获取锁。而Lock则提供超时锁和可中断等更加灵活的方式在未能获取锁的 条件下提供一种退出的机制。一个锁内部可以有多个Condition实例即有多路条件队列而synchronize只有一路条件队列同样Condition也提供灵活的阻塞方式在未获得通知之前可以通过中断线程以 及设置等待时限等方式退出条件队列。synchronize对线程的同步仅提供独占模式而Lock即可以提供独占模式也可以提供共享模式synchronizedLock关键字类自动加锁和释放锁需要手动调用unlock方法释放锁jvm层面的锁API层面的锁非公平锁可以选择公平或者非公平锁锁是一个对象,并且锁的信息保存在了对象中代码中通过int类型的state标识有一个锁升级的过程无13、了解ConcurrentHashMap吗 为什么性能比HashTable高说下原理 难度系数⭐⭐ConcurrentHashMap是线程安全的Map容器JDK8之前ConcurrentHashMap使用锁分段技术将数据分成一段段存储每个数据段配置一把锁即segment类这个类继承ReentrantLock来保证线程安全JKD8的版本取消Segment这个分段锁数据结构底层也是使用Node数组链表红黑树从而实现对每一段数据就行加锁也减少了并发冲突的概率。hashtable类基本上所有的方法都是采用synchronized进行线程安全控制高并发情况下效率就降低 ConcurrentHashMap是采用了分段锁的思想提高性能锁粒度更细化14、ConcurrentHashMap底层原理 难度系数⭐⭐⭐Java7 中 ConcurrentHashMap 使用的分段锁也就是每一个 Segment 上同时只有一个线程可以操作每一个 Segment 都是一个类似 HashMap 数组的结构它可以扩容它的冲突会转化为链表。但是 Segment 的个数一但初始化就不能改变。public V put(K key, V value) {SegmentK,V s;if (value null)throw new NullPointerException();int hash hash(key);// hash 值无符号右移 28位初始化时获得然后与 segmentMask15 做与运算// 其实也就是把高4位与segmentMask1111做与运算// this.segmentMask ssize - 1;//对hash值进行右移segmentShift位计算元素对应segment中数组下表的位置//把hash右移segmentShift相当于只要hash值的高32-segmentShift位右移的目的是保留了hash值的高位。然后和segmentMask与操作计算元素在segment数组中的下表int j (hash segmentShift) segmentMask;//使用unsafe对象获取数组中第j个位置的值后面加上的是偏移量if ((s (SegmentK,V)UNSAFE.getObject // nonvolatile; recheck(segments, (j SSHIFT) SBASE)) null) // in ensureSegment// 如果查找到的 Segment 为空初始化s ensureSegment(j);//插入segment对象return s.put(key, hash, value, false);}/*** Returns the segment for the given index, creating it and* recording in segment table (via CAS) if not already present.** param k the index* return the segment*/SuppressWarnings(unchecked)private SegmentK,V ensureSegment(int k) {final SegmentK,V[] ss this.segments;long u (k SSHIFT) SBASE; // raw offsetSegmentK,V seg;// 判断 u 位置的 Segment 是否为nullif ((seg (SegmentK,V)UNSAFE.getObjectVolatile(ss, u)) null) {SegmentK,V proto ss[0]; // use segment 0 as prototype// 获取0号 segment 里的 HashEntryK,V 初始化长度int cap proto.table.length;// 获取0号 segment 里的 hash 表里的扩容负载因子所有的 segment 的 loadFactor 是相同的float lf proto.loadFactor;// 计算扩容阀值int threshold (int)(cap * lf);// 创建一个 cap 容量的 HashEntry 数组HashEntryK,V[] tab (HashEntryK,V[])new HashEntry[cap];if ((seg (SegmentK,V)UNSAFE.getObjectVolatile(ss, u)) null) { // recheck// 再次检查 u 位置的 Segment 是否为null因为这时可能有其他线程进行了操作SegmentK,V s new SegmentK,V(lf, threshold, tab);// 自旋检查 u 位置的 Segment 是否为nullwhile ((seg (SegmentK,V)UNSAFE.getObjectVolatile(ss, u)) null) {// 使用CAS 赋值只会成功一次if (UNSAFE.compareAndSwapObject(ss, u, null, seg s))break;}}}return seg;}final V put(K key, int hash, V value, boolean onlyIfAbsent) {// 获取 ReentrantLock 独占锁获取不到scanAndLockForPut 获取。HashEntryK,V node tryLock() ? null : scanAndLockForPut(key, hash, value);V oldValue;try {HashEntryK,V[] tab table;// 计算要put的数据位置int index (tab.length - 1) hash;// CAS 获取 index 坐标的值HashEntryK,V first entryAt(tab, index);for (HashEntryK,V e first;;) {if (e ! null) {// 检查是否 key 已经存在如果存在则遍历链表寻找位置找到后替换 valueK k;if ((k e.key) key ||(e.hash hash key.equals(k))) {oldValue e.value;if (!onlyIfAbsent) {e.value value;modCount;}break;}e e.next;}else {// first 有值没说明 index 位置已经有值了有冲突链表头插法。if (node ! null)node.setNext(first);elsenode new HashEntryK,V(hash, key, value, first);int c count 1;// 容量大于扩容阀值小于最大容量进行扩容if (c threshold tab.length MAXIMUM_CAPACITY)rehash(node);else// index 位置赋值 nodenode 可能是一个元素也可能是一个链表的表头setEntryAt(tab, index, node);modCount;count c;oldValue null;break;}}} finally {unlock();}return oldValue;}JavaJava8 中的 ConcurrentHashMap 使用的 Synchronized 锁加 CAS 的机制。结构Node 数组 链表 / 红黑树Node 是类似于一个 HashEntry 的结构。它的冲突再达到一定大小时会转化成红黑树在冲突小于一定数量时又退回链表。篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1hopublic V put(K key, V value) {return putVal(key, value, false);}/** Implementation for put and putIfAbsent */final V putVal(K key, V value, boolean onlyIfAbsent) {// key 和 value 不能为空if (key null || value null) throw new NullPointerException();int hash spread(key.hashCode());int binCount 0;for (NodeK,V[] tab table;;) {// f 目标位置元素NodeK,V f; int n, i, fh;// fh 后面存放目标位置的元素 hash 值if (tab null || (n tab.length) 0)// 数组桶为空初始化数组桶自旋CAS)tab initTable();else if ((f tabAt(tab, i (n - 1) hash)) null) {// 桶内为空CAS 放入不加锁成功了就直接 break 跳出if (casTabAt(tab, i, null,new NodeK,V(hash, key, value, null)))break; // no lock when adding to empty bin}else if ((fh f.hash) MOVED)tab helpTransfer(tab, f);else {V oldVal null;// 使用 synchronized 加锁加入节点synchronized (f) {if (tabAt(tab, i) f) {// 说明是链表if (fh 0) {binCount 1;// 循环加入新的或者覆盖节点for (NodeK,V e f;; binCount) {K ek;if (e.hash hash ((ek e.key) key ||(ek ! null key.equals(ek)))) {oldVal e.val;if (!onlyIfAbsent)e.val value;break;}NodeK,V pred e;if ((e e.next) null) {pred.next new NodeK,V(hash, key,value, null);break;}}}else if (f instanceof TreeBin) {// 红黑树NodeK,V p;binCount 2;if ((p ((TreeBinK,V)f).putTreeVal(hash, key,value)) ! null) {oldVal p.val;if (!onlyIfAbsent)p.val value;}}}}if (binCount ! 0) {if (binCount TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal ! null)return oldVal;break;}}}addCount(1L, binCount);return null;}15、了解volatile关键字不 难度系数⭐volatile是Java提供的最轻量级的同步机制保证了共享变量的可见性被volatile关键字修饰的变量如果值发生了变化其他线程立刻可见避免出现脏读现象。volatile禁止了指令重排可以保证程序执行的有序性但是由于禁止了指令重排所以JVM相关的优化没了效率会偏弱16、synchronized和volatile有什么区别 难度系数⭐⭐volatile本质是告诉JVM当前变量在寄存器中的值是不确定的需要从主存中读取synchronized则是锁定当前变量只有当前线程可以访问该变量其他线程被阻塞住。volatile仅能用在变量级别而synchronized可以使用在变量、方法、类级别。volatile仅能实现变量的修改可见性不能保证原子性而synchronized则可以保证变量的修改可见性和原子性。volatile不会造成线程阻塞synchronized可能会造成线程阻塞。volatile标记的变量不会被编译器优化synchronized标记的变量可以被编译器优化。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

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

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

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…