
Java面试
文章平均质量分 83
Java面试
@程序员小袁
你说 然后呢 憋说话,让我静静
展开
-
class 文件分析
Java 是跨平台的,JVM 作为中间层,自然要针对不同的操作系统提供不同的实现。通过不同操作系统的 JVM,源代码就可以不用根据不同的操作系统编译成不同的二进制可执行文件了,跨平台的目标也就实现了。那这个 class 文件到底是什么玩意呢?它是怎么被 JVM 识别的呢?编写一段简单的 Java 代码,文件名为 Hello.java。点击编译按钮后,IDEA 会自动生成一个名为 Hello.class 的文件,在的对应包目录下。原创 2024-10-10 09:20:37 · 746 阅读 · 0 评论 -
Java 8 的内存结构
由于java是一门高级语言,离硬件底层比较远,有时候无法操作底层的资源,于是,java添加了native关键字,被native关键字修饰的方法可以用其他语言重写,这样,就可以写一个本地方法,然后用C语言重写,这样来操作底层资源。当然,使用了native方法会导致系统的可移植性不高,这是需要注意的。int a=1;//这个1便是字面量//iloveu便是字面量。原创 2024-10-10 09:19:37 · 677 阅读 · 0 评论 -
为什么用元空间替换永久代
首先需要明确的是,以下讨论的HotSpot虚拟机,其他类型的虚拟机,例如JRockit与J9等,压根就没有永久代的概念。因此,下面所说的“虚拟机”都是HotSpot版本的。要想理解这种变化的原因,需要先理解方法区、永久代与元空间的概念与之间的关系。原创 2024-10-09 09:09:41 · 1988 阅读 · 0 评论 -
Java 类加载的几个阶段
如果要查找类加载器,通过方法可以获取。从运行结果可以看到,当前的类加载器是,它的上一级是,再上一级是null。其实的上一级是有类加载器的,它叫Bootstrap ClassLoader,是一个启动类加载器,由 C++ 实现,不是 ClassLoader 子类,因此以 null 作为结果返回。这几种类加载器的层次关系,可以用如下图来描述。在虚拟机启动后,会优先初始化Bootstrap Classloader。原创 2024-10-08 09:21:12 · 1195 阅读 · 0 评论 -
Java 类加载过程
开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。原创 2024-10-07 08:42:28 · 1085 阅读 · 0 评论 -
Java内存区域
Java内存区域。原创 2024-10-07 08:41:55 · 759 阅读 · 0 评论 -
JVM 内存布局
我们先来说堆。堆是 OOM 故障最主要的发生区域。它是内存区域中最大的一块区域,被所有线程共享,存储着几乎所有的实例对象、数组。所有的对象实例以及数组都要在堆上分配,但是随着 JIT 编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”。从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以 Java 堆中还可以细分为:新生代和老年代。原创 2024-10-07 08:41:26 · 1056 阅读 · 0 评论 -
Java类的生命周期浅析
简单一句话概括,类的加载阶段就是:找到需要加载的类并把类的信息加载到jvm的方法区中,然后在堆区中实例化一个java.lang.Class对象,作为方法区中这个类的信息的入口。那简单来说,java类被jvm进行加载到卸载的过程,就是java类的一生,称之为java类的生命的周期。jvm对类的加载时机没有明确规范,但对类的初始化时机有:只有当类被直接引用的时候,才会触发类的初始化。区别于对象的初始化,类的初始化所做的一起都是基于类变量或类语句的,也就是说执行的都是共性的抽象信息。类就是对象实例的抽象。原创 2024-10-06 12:39:52 · 835 阅读 · 0 评论 -
深入理解 Java 对象的内存布局
介绍了 Java 对象在 JVM 中的内存布局,整体可以分为:对象头、实例数据、对齐填充三个部分。第一部分的对象头包括了对象运行时数据和类型指针。其中对象运行时数据包括:哈希码、GC 分代年龄、锁状态标志等,类型指针指向对象类型元数据,确定对象是哪个类的实例。第二部分是实例数据,是真正存储的有效信息,包括各个类型的字段。第三部分是对齐填充,因为 JVM 要求对象起始地址必须是 8 字节的整数倍,所以必须有对齐填充来占位。原创 2024-10-06 11:15:36 · 819 阅读 · 0 评论 -
JVM 内存区域划分
在谈 JVM 内存区域划分之前,先来看一下 Java 程序的具体执行过程,画了一幅图。Java 源代码文件经过编译器编译后生成字节码文件,然后交给 JVM 的类加载器,加载完毕后,交给执行引擎执行。在整个执行的过程中,JVM 会用一块空间来存储程序执行期间需要用到的数据,这块空间一般被称为运行时数据区,也就是常说的 JVM 内存。所以,在谈 JVM 内存区域划分的时候,其实谈的就是这块空间——运行时数据区。了解官方出品的《Java 虚拟机规范》规范可以更方便地深入地理解 JVM。原创 2024-10-05 09:48:56 · 610 阅读 · 0 评论 -
6 个 Java 工具,轻松分析定位 JVM 问题
其中,S0 表示 Survivor0 区占用百分比,S1 表示 Survivor1 区占用百分比,E 表示 Eden 区占用百分比,O 表示老年代占用百分比,M 表示元数据区占用百分比,YGC 表示年轻代回收次数,YGCT 表示年轻代回收耗时,FGC 表示老年代回收次数,FGCT 表示老年代回收耗时。jstat 定时输出的特性,可以方便持续观察程序的各项指标。同样,如果没有条件使用图形界面(毕竟在 Linux 服务器上,主要使用命令行工具),又希望看到 GC 趋势的话,可以使用 jstat 工具。原创 2024-10-04 11:16:09 · 725 阅读 · 0 评论 -
如何在Spring Boot中有条件地运行CommandLineRunner Bean
PS 使用 Spring Boot 3.1.2 进行测试。原创 2024-10-04 11:15:42 · 457 阅读 · 0 评论 -
强大的JVM监控工具
在生产环境中,经常会遇到各种各样奇葩的性能问题,所以掌握最基本的JVM命令行监控工具还是很有必要的名称主要作用jps查看正在运行的Java进程jstack打印线程快照jmap导出堆内存映像文件jstat查看jvm统计信息jinfo实时查看和修改jvm配置参数jhat用于分析heapdump文件。原创 2024-10-03 08:29:32 · 1173 阅读 · 0 评论 -
Java的栈帧和动态链接是什么?
在 Java 的面试过程中,不可避免的一个面试题那就是 JVM,而 JVM 的面试题中,有各种,比如在堆中会被问到的关于垃圾回收机制的相关问题,在栈中会被问到入栈以及出栈的过程,来聊一下关于栈的相关问题,比如,栈帧和动态链接指的是什么?总的来说,符号引用转为直接引用是Java类加载过程中解析阶段的一个重要步骤,它确保了符号引用能够被正确地解析为内存中的直接引用,从而实现Java程序的正常运行。:指向运行时常量池的方法引用,使得方法中的符号引用在运行时可以直接定位到引用的目标,比如某个类的成员或者方法。原创 2024-10-01 09:20:38 · 871 阅读 · 0 评论 -
new一个对象背后发生了什么?
Java在new一个对象的时候,会先查看对象所属的类有没有被加载到内存,如果没有的话,就会先通过类的全限定名来加载。加载并初始化类完成后,再进行对象的创建工作。先假设是第一次使用该类,这样的话new一个对象就可以分为两个过程:加载并初始化类和创建对象。原创 2024-09-30 09:11:25 · 1474 阅读 · 0 评论 -
JDK 内置实用工具:监视、故障排除
Javacore,也可以称为“threaddump”或是“javadump”,它是 Java 提供的一种诊断特性,能够提供一份可读的当前运行的 JVM 中线程使用情况的快照。即在某个特定时刻,JVM 中有哪些线程在运行,每个线程执行到哪一个类,哪一个方法。应用程序如果出现不可恢复的错误或是内存泄露,就会自动触发 Javacore 的生成。原创 2024-09-29 17:34:46 · 1195 阅读 · 0 评论 -
JVM相关的命令汇总
虽然目前市场上有很多成熟的 JVM 可视化监控分析工具,但是所有的工具其实都依赖于 JDK 的接口和底层相关的命令,了解这些命令的使用对于在紧急情况下排查 JVM 相关的线上故障,会有更加直观的帮助。下面一起来看看 JVM 常用的命令有哪些。原创 2024-09-29 17:30:02 · 1612 阅读 · 0 评论 -
九大 Java 性能优化工具
JProfiler集CPU、内存和线程性能分析于一体,可以用于分析性能瓶颈、内存泄漏、CPU负载和解决线程相关的问题,并且支持本地性能分析(分析与JProfiler软件安装在同一台机的应用)和远程性能分析(它可以分析远程没有安装JProfiler机器上的应用),这一点对开发人员非常有用。生成的数据可以由JDK工具生成和读取,多个Java程序的所有数据和信息都可以很方便地进行查看,包括本地和远程的运行程序。它更适合作为一个分析Java堆栈和计算大小的工具集,也可以用于监测内存泄漏和反模式带来的内存损耗。原创 2024-09-28 21:18:44 · 969 阅读 · 0 评论 -
Java面试题之JVM之垃圾回收
Serial收集器:单线程的收集器,收集垃圾时,必须stop the world,使用复制算法。ParNew收集器:Serial收集器的多线程版本,也需要stop the world,复制算法。Parallel Scavenge收集器:新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞吐量。如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%。Serial Old收集器:是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。原创 2024-09-27 09:09:56 · 675 阅读 · 0 评论 -
Java面试之JVM之内存模型
类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。原创 2024-09-27 09:09:11 · 623 阅读 · 0 评论 -
java -jar命令能够启动项目的原理
JAR(Java Archive)文件是一种包含 Java 类文件、资源文件和元数据的归档文件格式。一个典型的 Java 项目经过编译打包后会生成一个 JAR 文件,其中包含了项目的所有编译后的类文件、配置文件、静态资源等。“java -jar”命令能够启动项目是因为它利用了 Java 虚拟机的强大功能,通过加载 JAR。这个 jar 是从 start.spring.io 上下载下来的一个最简单的 demo 打包来的。项目可以方便地打包和分发,并且可以在不同的平台上通过相同的命令来启动运行。原创 2024-09-25 13:30:54 · 496 阅读 · 0 评论 -
Java中关于6张表或者多张表关联查询的接口怎么优化
方法使用了异步查询和结果合并的方式进行分表查询优化。首先,定义了一个子查询列表,每个子查询使用。然后,等待所有子查询完成,并将结果合并到一个列表中返回。先去找产品对业务,看是否是业务不对,然后再考虑优化。原创 2024-09-25 13:30:33 · 692 阅读 · 0 评论 -
Java中象拷贝的两种方式:深拷贝与浅拷贝
另外,也可以通过序列化的方式实现深拷贝,但这种方式相对复杂一些。深拷贝和浅拷贝在不同的场景下有不同的用途,需要根据具体的需求来选择合适的拷贝方式。原创 2024-09-22 19:23:31 · 585 阅读 · 0 评论 -
分布式系统的CAP原理
一致性(Consistency):对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。在分布式系统中,这意味着所有的数据备份在同一时刻具有相同的值,等同于所有节点访问同一份最新的数据副本。例如,在一个分布式数据库系统中,当一个用户在某个节点上更新了一条数据记录后,其他节点上的用户在读取该数据时,应该能够立即获取到最新的值。可用性(Availability):任何客户端的请求都能得到响应数据,不会出现响应错误。原创 2024-09-22 19:15:49 · 421 阅读 · 0 评论 -
Java基础之JDBC
JDBC的全称是Java DataBase Connection,也就是Java数据库连接,可以用它来操作关系型数据库。JDBC接口及相关类在java.sql包和javax.sql包里。可以用它来连接数据库,执行SQL查询,存储过程,并处理返回的结果。原创 2024-09-21 08:23:39 · 716 阅读 · 0 评论 -
ThreadLocal引发内存泄漏的原因及解决方案
【代码】ThreadLocal引发内存泄漏的原因及解决方案。原创 2024-09-21 08:23:13 · 1058 阅读 · 0 评论 -
Java基础之IO流
它是一种数据的流从源头流到目的地。比如文件拷贝,输入流和输出流都包括了。输入流从文件中读取数据存储到进程(process)中,输出流从进程中读取数据然后写入到目标文件。是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。原创 2024-09-20 08:07:58 · 644 阅读 · 0 评论 -
【多线程解码】Java 死锁的发生条件与解决途径
在 Java 中,死锁是指两个或多个线程被永久阻塞,它们都在等待被其他线程占用的资源,从而导致程序无法继续执行下去的情况。可以使用jps、jstack查看死锁信息,堆栈信息需要往下找找。原创 2024-09-20 08:07:12 · 1217 阅读 · 0 评论 -
线程池的核心线程会被回收吗?
但是ThreadPoolExecutor 还是提供了一个参数来控制这个行为,通过allowCoreThreadTimeOut(true)设置后,核心线程在空闲超过`keepAliveTime时就会被回收。从processWorkerExit() 中可以看出,如果allowCoreThreadTimeOut 设置为true,则大概率情况下是不会调用addWorker(null, false) 去创建线程的,它会直接返回,线程自然消亡。原创 2024-09-19 10:27:00 · 631 阅读 · 0 评论 -
Java中代理模式相关的注解有哪些
代理主题持有一个真实主题的引用,在调用真实主题的方法前后可以添加一些额外的操作,比如权限控制、日志记录、缓存等,从而实现对真实主题的间接访问和控制。后,Spring 会创建一个代理对象,在代理对象中检查缓存是否存在,如果存在则直接返回缓存结果,否则执行方法并将结果存入缓存。后,Spring 会在运行时为该方法创建一个代理对象,在代理对象中实现事务的开启、提交或回滚等操作。:定义了真实主题和代理主题的公共接口,客户端通过这个接口来调用真实主题或者代理主题的方法。:真正实现业务逻辑的对象。原创 2024-09-19 10:26:24 · 340 阅读 · 0 评论 -
Java基础之-多线程
死锁是指多个线程因竞争资源而造成的一种互相等待状态,若无外力作用,这些进程都将无法向前推进。Java在JDK1.5之前都是靠synchronized关键字保证同步的,这种通过使用一致的锁定协议来协调对共享状态的访问,可以确保无论哪个线程持有共享变量的锁,都采用独占的方式来访问这些变量。独占锁其实就是一种悲观锁,所以可以说synchronized是悲观锁。CAS(compare and swap)的缩写。Java利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法,实现原子操作。原创 2024-09-18 07:13:41 · 740 阅读 · 0 评论 -
Java线程面试题合集
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,可以使用多线程对运算密集型任务提速。比如,如果一个线程完成一个任务要100毫秒,那么用十个线程完成该任务只需10毫秒。如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。原创 2024-09-17 08:15:05 · 875 阅读 · 0 评论 -
Java中Redis大Key的优化拆分方案与示例
如果是大字符串,可以考虑将其拆分成多个小字符串存储。比如将一个很长的 JSON 字符串拆分成多个小的 JSON 片段分别存储。对于大哈希,可以将其属性拆分成多个小哈希存储。比如一个包含大量字段的哈希表,可以根据字段的某种特征进行拆分。对于大列表,可以将其拆分成多个小列表存储。比如一个有大量元素的列表,可以根据一定规则拆分成多个子列表。通过以上拆分方案,可以有效地避免 Redis 中的大 key 问题,提高系统的性能和稳定性。原创 2024-09-17 08:14:41 · 686 阅读 · 0 评论 -
Java21新特性
通过高效地调用外部函数(即 JVM 之外的代码)和安全地访问外部内存(即不受 JVM 管理的内存),该 API 使 Java 程序能够调用本机库并处理本机数据,而不会像 JNI 那样危险和脆弱。,这是一种具有确定出现顺序(encounter order)的集合(无论我们遍历这样的集合多少次,元素的出现顺序始终是固定的)。在未来的版本中,官方会把 ZGenerational 设为默认值,即默认打开 ZGC 的分代 GC。表示未命名的变量以及模式匹配时不使用的组件,旨在提高代码的可读性和可维护性。原创 2024-09-16 07:56:01 · 943 阅读 · 0 评论 -
多线程面试题-60题
死锁就是两个线程相互等待对方释放对象锁。很简单,简单看名字就知道是装有线程的池子,可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程的复用。死锁、活锁、饥饿是关于多线程是否活跃出现的运行阻塞障碍问题,如果线程出现了这三种情况,即线程不再活跃,不能再正常地执行下去了。原子性、可见性、有序性是多线程编程中最重要的几个知识点,由于多线程情况复杂,如何让每个线程能看到正确的结果,这是非常重要的。什么是守护线程?原创 2024-09-16 07:55:26 · 986 阅读 · 0 评论 -
多线程面试题-28问
字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。所以,程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。原创 2024-09-14 12:34:23 · 779 阅读 · 0 评论 -
Java静态代理和动态代理
给大家举个简单例子。在一个公司中,老板处于上层,客户在下层。因每天来访客户众多,老板本应只考虑战略和赚钱,却被一些不重要的客户耽误不少时间。于是老板招聘了一个秘书,专门负责接待客户和登记客户来访。这就如同我们的代码,业务类只需负责核心业务代码,非业务代码如请求用时记录、事务开启、健全及异常处理等,交给代理去做,从而降低代码耦合度,将业务代码和公共代码分离,提高可维护性。这个例子属于静态代理,因为招来的秘书只负责客户来访登记。原创 2024-09-14 12:33:43 · 870 阅读 · 0 评论 -
Java中的锁
开发过程中,最常见的就是互斥锁的了,互斥锁加锁失败时,会用「线程切换」来应对,当加锁失败的线程再次加锁成功后的这一过程,会有两次线程上下文切换的成本,性能损耗比较大。如果明确知道被锁住的代码的执行时间很短,那应该选择开销比较小的自旋锁,因为自旋锁加锁失败时,并不会主动产生线程切换,而是一直忙等待,直到获取到锁,那么如果被锁住的代码执行时间很短,那这个忙等待的时间相对应也很短。如果能区分读操作和写操作的场景,那读写锁就更合适了,它允许多个读线程可以同时持有读锁,提高了读的并发性。原创 2024-09-13 12:22:52 · 807 阅读 · 0 评论 -
多线程和高并发-17题
ThreadLocal 用于创建线程的本地变量,一个对象的所有线程会共享它的全局变量,所以这些变量不是线程安全的,可以使用同步技术。但是当不想使用同步的时候,可以选择 ThreadLocal变量。每个线程都会拥有他们自己的 Thread 变量,它们可以使用 get()\set() 方法去获取他们的默认值或者在线程内部改变他们的值。ThreadLocal 实例通常是希望它们同线程状态关联起来是 private static 属性。当所有线程阻塞,或者由于需要的资源无效而不能处理,不存在非阻塞线程使资源可用。原创 2024-09-12 12:18:23 · 776 阅读 · 0 评论 -
14个必问的 多线程&并发 面试题
在多线程环境中,能永远保证程序的正确性。执行结果不存在二义性。说白了,运行多少次结果都是一致的。换种说法,当多个线程访问某一个类(对象或方法)时,这个类始终都能表现心正确的行为,那么这个类(对象或方法)就是线程安全的。使用关键字和使用锁。线程池就是预先创建一些线程,它们的集合称为线程池。线程池可以很好地提高性能,在系统启动时即创建大量空闲的线程,程序将一个task给到线程池,线程池就会启动一条线程来执行这个任务,执行结束后,该线程不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。原创 2024-09-11 10:52:31 · 773 阅读 · 0 评论