Java 线程池内部任务出异常后,如何知道是哪个线程出了异常?重点回答默认情况下,线程池不会直接报告哪个线程发生了异常,但是可以采取以下几种方法:
1)**自定义线程池的 ThreadFactory**:
通过自定义 ThreadFactory,为每个线程设置一个异常处理器(UncaughtExceptionHandler),在其中记录发生异常的线程信息。
2)**使用 Future**...
Java 中 Thread.sleep 和 Thread.yield 的区别?回答重点Thread.sleep() 和 Thread.yield() 都是用于控制线程行为的两个方法。
**Thread.sleep()**:
使当前线程进入休眠状态(TIMED_WAITING 状态),暂停执行指定的时间(以毫秒为单位)。在休眠期间,线程不会占用 CPU 时间片。休眠结束后,线程会尝试重新获取...
Java 线程池中 shutdown 与 shutdownNow 的区别是什么?重点回答shutdown() 和 shutdownNow() 都用于关闭线程池,但工作方式有所不同:
1)**shutdown()**:
启动线程池的平滑关闭。它不再接受新的任务,但会继续执行已经提交的任务(包括在队列中的任务)。
线程池会进入 SHUTDOWN 状态,所有已执行和正在执行的任务都会继续完成,只有...
在 Java 中主线程如何知晓创建的子线程是否执行成功?回答重点1)**使用 Thread.join()**:
主线程通过调用 join() 方法等待子线程执行完毕。子线程正常结束,说明执行成功,若抛出异常则需要捕获处理。
2)**使用 Callable 和 Future**:
通过 Callable 创建可返回结果的任务,并通过 Future.get() 获取子线程的执行结果或捕获异...
Java 线程池核心线程数在运行过程中能修改吗?如何修改?回答重点可以动态修改的。Java 的 ThreadPoolExecutor 提供了动态调整核心线程数和最大线程数的方法。
1)修改核心线程数的方法:
使用 ThreadPoolExecutor.setCorePoolSize(int corePoolSize) 方法可以动态修改核心线程数。corePoolSize 参数代表线程池中的...
Java 中如何创建多线程?回答重点常见有以下五种方式创建使用多线程:
1)实现 Runnable 接口:
实现 Runnable 接口的 run() 方法,使用 Thread 类的构造函数传入 Runnable 对象,调用 start() 方法启动线程。
例子:Thread thread = new Thread(new MyRunnable()); thread.start();
2...
什么是 Java 中的线程同步?回答重点线程同步是指在多线程环境下,为了避免多个线程对共享资源进行同时访问,从而引发数据不一致或其他问题的一种机制。它通过对关键代码段加锁,使得同一时刻只有一个线程能够访问共享资源。
当多个线程共享同一资源(如变量、对象或文件)时,若没有同步机制,可能会导致竞态条件,即线程对共享资源的操作是非原子性的,多个线程之间可能会同时修改数据,导致结果不符合预期。
扩展...
Java 里的对象在虚拟机里面是怎么存储的?回答重点Java 对象在虚拟机中的存储由以下几个部分组成:
对象头(Header):包含对象的元信息和运行时数据。主要由以下三部分构成:
Mark Word:用于存储运行时数据,例如对象的哈希码(HashCode)、GC 标记信息、锁状态标志等。它是一个多功能字段,会根据对象的状态动态变化。
类型指针(Class Pointer):指向对象...
说说 Java 的执行流程?回答重点Java 程序的执行流程经历了从编译到字节码的生成,再到类加载和 JIT 编译的过程,最终在 JVM 中执行。并且在程序运行过程中,JVM 负责内存管理、垃圾回收和线程调度等工作。
主要流程如下:
源代码:编写 .java 文件。
编译:使用 javac 编译器生成 .class 字节码文件。
类加载:JVM 的类加载器加载 .class 文件到内存中。...
G1 相对于 CMS 有哪些进步的地方?回答重点可以从以下四个方面来回答:
从内存管理机制来看:
G1 将整个堆划分为多个大小相等的Region(默认最多2048个),物理上不再严格区分新生代和老年代,而是根据回收价值动态调整各区域的回收。这样避免了CMS因固定分代导致的内存碎片问题,提升了内存利用率。
从回收算法来看:
CMS 采用标记-清除算法,容易产生内存碎片,可能导致Full ...
JIT 编译后的代码存在哪?回答重点JIT(Just-In-Time)编译后的机器码通常存放在 Code Cache(代码缓存区,不在堆内) 中。
JVM 提供参数用于调整 Code Cache 的大小和行为:
-XX:InitialCodeCacheSize:初始大小。
-XX:ReservedCodeCacheSize:最大大小。
-XX:+PrintCodeCache:打印 Code...
Java 是如何实现跨平台的?回答重点Java 程序在编译后生成字节码(.class 文件),而不是直接生成特定于某一操作系统的机器代码。
在不同操作系统上都有各自实现的 JVM,负责将字节码翻译为特定平台的机器代码并执行。这使得同一份 Java 字节码可以在任何支持 JVM 的平台上运行。
扩展知识进一步理解跨平台所谓的跨平台主要指的是在不同的硬件或操作系统上,Java 代码都可以运行,不...
JVM 的内存区域是如何划分的?回答重点Java 虚拟机运行时数据区分为方法区、堆、虚拟机栈、本地方法栈、程序计数器。
1)方法区(Method Area):
存储类信息、常量、静态变量和即时编译器(JIT)编译后的代码。
属于线程共享区域,所有线程共享方法区内存。
在 JDK 8 之前,HotSpot 使用永久代(PermGen)来实现方法区,JDK 8 之后被元空间(Metaspace...
编译执行与解释执行的区别是什么?JVM 使用哪种方式?回答重点 编译执行:是指程序在执行之前,首先通过编译器将源代码编译为机器代码,然后直接在 CPU 上运行。常见的编译语言如 C、C++。
优点:编译后的程序运行速度快,因为机器代码是针对目标平台直接生成的,且不需要在运行时再进行翻译。
缺点:程序必须针对每个平台重新编译,跨平台性差;另外,编译后生成的机器代码难以调试和逆向工程。
解释...
Java 中堆和栈的区别是什么?回答重点栈(Stack):主要用于存储局部变量和方法的调用信息(如返回地址、参数等)。在方法执行期间,局部变量(包括引用变量,但不包括它们引用的对象)被创建在栈上,并在方法结束时被销毁。
堆(Heap):用于存储对象实例和数组。每当使用 new 关键字创建对象时,JVM 都会在堆上为该对象分配内存空间。
扩展知识从其他方面进一步区分
生命周期:我们知道JVM里...
什么是 Java 中的直接内存(堆外内存)?回答重点Java 中的直接内存(Direct Memory)是由操作系统分配的内存区域,它不受 JVM 堆内存管理限制(是堆外内存)。直接内存是通过 java.nio 包中的 ByteBuffer.allocateDirect() 方法分配的,它可以绕过 JVM 垃圾回收机制,直接与本地系统内存交互。
扩展知识直接内存的优势 由于直接内存不需要...
什么是 Java 中的 JIT(Just-In-Time)?回答重点Java 中的 JIT(Just-In-Time,即时编译)编译器是一种在程序运行时将字节码转换为机器码的技术。因为这种转换是在程序运行时即时进行的,因此得名“Just-In-Time”。
它在 Java 程序运行的时候,发现热点代码(频繁执行的代码段)时,就将这段代码编译成机器码,减少解释执行的开销,使得 Java 代码接...
什么是 Java 的 AOT(Ahead-Of-Time)?回答重点Java 的 AOT(Ahead-Of-Time,预编译)是一种在程序运行之前,将 Java 字节码直接编译为本地机器码的技术。
JIT 是在 Java 运行时将一些代码编译成机器码,而 AOT 则是在代码运行之前就编译成机器吗,也就是提前编译。
提前编译的好处是减少运行时编译的开销,且减少程序启动所需的编译时间,提高启动速...
什么是 Java 中的常量池?回答重点 Java 中的常量池(Constant Pool)是一块存储用于运行时的常量或符号的区域。它主要存在于两种地方:
运行时常量池:在每个类或接口的 Class 文件中存储编译时生成的常量信息,并在类加载时进入 JVM 方法区(Java 8 之后是 metaspace)。
字符串常量池:用于存储字符串字面量,位于堆内存中的一块特殊区域。通过 String...
你了解 Java 的逃逸分析吗?回答重点逃逸分析(Escape Analysis)是 Java 编译器的优化技术,用于确定一个对象的作用范围,即分析对象是否会逃逸出当前方法或线程的作用范围。如果对象不会逃逸,JVM 可以实现栈上分配、同步消除、标量替换等优化,减少内存分配开销和同步开销,从而提高应用的性能。
逃逸的两种类型:
方法逃逸:如果一个对象在方法内部创建,并作为返回值或通过参数传递...
Java 中如何判断对象是否是垃圾?不同垃圾回收方法有何区别?回答重点主要通过以下两种方式来实现:
1. 引用计数法(Reference Counting):
每个对象维护一个引用计数器,引用计数增加时,计数器加 1,减少时,计数器减 1。当引用计数器为 0 时,说明该对象不再被引用,可以被回收。
优点:实现简单,实时性好。
缺点:无法处理循环引用的问题,两个对象互相引用时,引用计数器永远不...
Java 中常见的垃圾收集器有哪些?回答重点分为新生代收集器和老年代收集器来看,常见的垃圾收集器包括:
新生代垃圾收集器:1)Serial 收集器:
单线程收集器,适合小型应用和单处理器环境。
触发 Stop-The-World(STW)操作,所有应用线程在 GC 时暂停。
适用场景:适用于单线程应用和客户端模式。
2)ParNew 收集器:
是 Serial 收集器的多线程版本,能够...
为什么 Java 的垃圾收集器将堆分为老年代和新生代?回答重点主要是为了提高垃圾回收效率,依据对象的生命周期特点来进行优化。
对象的生命周期特点:
大多数对象存活时间短:大部分对象会很快变成垃圾,不再被使用,这些短生命周期的对象会分配在新生代。
少部分对象存活时间长:一些长期存活的对象不会很快被回收,分配在新生代的对象经过多次垃圾回收仍存活的,将晋升到老年代。
所以按照存活时间分区管理更...
为什么 Java 新生代被划分为 S0、S1 和 Eden 区?回答重点主要是为了提高新生代内存的利用率。
扩展知识详细分析因为新生代对象朝生夕死的特性,适合复制算法。按正常思路将新生代一分为二,划两块区域,每次只使用其中一个,GC 后将存活的复制到另一个区域,然后清理老区域非存活对象,这样替换使用两块区域可以避免内存碎片的存在。
但如果一分为二的话,空间利用率只有一半了(每次分配对象只能...
什么是三色标记算法?回答重点三色标记算法 是现代垃圾回收器中常用的一种 增量标记算法,它通过“白-灰-黑”三种颜色标记对象的状态可以与应用线程并发执行的同时确保程序的内存管理安全。
它用于标记哪些对象需要被回收,哪些对象需要保留,减少一次性停顿带来的性能影响。非常适合 低延迟 和 实时垃圾回收 的场景。
它通过将对象分为三种颜色来进行标记和追踪。
三色标记的基本概念:
白色对象:表示还没有...
Java 中的 young GC、old GC、full GC 和 mixed GC 的区别是什么?回答重点Young GC(Minor GC 或 YGC),即年轻代垃圾回收:
作用范围:仅针对新生代(Eden 和 S0/S1)。
触发条件:当新生代内存(尤其是 Eden 区)被填满时触发。
执行方式:只回收新生代中的对象,老年代不受影响。
特点:回收频率较高,回收时间较短,因为...
什么情况下会触发 Java 的 Full GC?回答重点以下几种情况可能会触发 Full GC:
1)老年代空间不足:
当老年代空间不足时(且无法通过老年代垃圾回收释放足够空间),会触发 Full GC 来回收老年代中的对象。
2)永久代或元空间空间不足:
在 Java 8 之前,如果永久代(PermGen)空间不足,会触发 Full GC。Java 8 之后,永久代被移除,元空间(M...
JVM 的 TLAB(Thread-Local Allocation Buffer)是什么?回答重点TLAB(Thread-Local Allocation Buffer)是 JVM 中为每个线程分配的一小块堆内存,用于加速对象的分配操作。每个线程都有自己的 TLAB,,大大加速了内存分配的同时避免了多线程竞争共享堆内存时的同步开销。
工作原理:
每个线程在执行过程中优先从自己的 TLAB...
什么条件会触发 Java 的 young GC?回答重点在 Java 中,Young GC(Minor GC) 是针对新生代(Young Generation)对象的垃圾回收。
主要有三种情况会会触发 Young GC:
1)Eden 区空间不足:
新生代被划分为三个区域:Eden 区、S0(Survivor 0) 区和 S1(Survivor 1) 区。大部分新创建的对象会先分配到 Ed...
什么是 Java 的 PLAB?回答重点PLAB(Promotion Local Allocation Buffer) 是 Java 垃圾回收器中的一种优化机制,主要用于 G1 垃圾收集器,目的是提高对象晋升(Promotion)到老年代时的效率。
在垃圾回收过程中,新生代中的某些对象由于生命周期较长,会被晋升到老年代。为了减少线程竞争和提升晋升效率,G1 为每个 GC 线程分配一个局部缓冲...