什么是 Java 的 StampedLock?回答重点StampedLock 是 Java 8 引入的一个锁机制,与传统的 ReentrantLock 和 ReadWriteLock 相比,StampedLock 通过引入乐观读锁和时间戳(stamp)的概念,提升了读写性能,尤其是在读多写少的场景下。
核心特性:
写锁(write lock):独占模式的锁,和 ReentrantLock ...
什么是 Java 的 CompletableFuture?回答重点CompletableFuture 是 Java 8 引入的一个强大的异步编程工具。允许非阻塞地处理异步任务,并且可以通过链式调用组合多个异步操作。
核心特性:
异步执行:使用 runAsync() 或 supplyAsync() 方法,可以非阻塞地执行任务。
任务的组合:可以使用 thenApply()、thenAccep...
什么是 Java 的 ForkJoinPool?重点Java的ForkJoinPool 是Java 7引入的一个专门用于并行执行任务的线程池,它采用“分而治之”(divide and conquer)算法来解决大规模的并行问题。
核心机制:
Fork(分解):任务被递归分解为更小的子任务,直到达到不可再分的程度。
Join(合并):子任务执行完毕后,将结果合并,形成最终的解决方案。
工作...
你使用过 Java 中的哪些原子类?回答重点Java 中的原子类是通过使用硬件提供的原子操作指令(如 CAS,Compare-And-Swap)来确保操作的原子性,从而避免线程竞争问题。
常用的原子类有以下几种:
AtomicInteger:用于操作整数的原子类,提供了原子性的自增、自减、加法等操作。
AtomicLong:与 AtomicInteger 类似,但用于操作 long 型数据...
你使用过 Java 中的哪些阻塞队列?回答重点阻塞队列主要用来阻塞队列的插入和获取操作,当队列满了的时候插入操作会被阻塞,直到队列有空位。当队列为空的时候获取操作会被阻塞,直到队列有值。
常用在实现生产者和消费者场景,在笔试题中比较常见。
常见的阻塞队列包括:
ArrayBlockingQueue:一个有界队列,底层基于数组实现。需要在初始化时指定队列的大小,队列满时,生产者会被阻塞,队...
如何在 Java 中控制多个线程的执行顺序?回答重点在 Java 中控制多个线程的执行顺序有很多种方法:
1) CompletableFuture,它内部有 thenRun 的方法,假设我们现在有三个任务T1、T2、T3 需要按序执行,那么仅需使用以下伪代码即可:
123CompletableFuture.runAsync(() -> {do t1 sth}) ...
Java 的 synchronized 是怎么实现的?回答重点synchronized 实现原理依赖于 JVM 的 Monitor(监视器锁) 和 对象头(Object Header)。
当 synchronized 修饰在方法或代码块上时,会对特定的对象或类加锁,从而确保同一时刻只有一个线程能执行加锁的代码块。
synchronized 修饰方法:会在方法的访问标志中增加一个 ACC_S...
Java 中的 synchronized 轻量级锁是否会进行自旋?回答重点轻量级锁 CAS 失败了之后,不会有自旋操作,会直接进入重量级锁膨胀过程。
扩展知识关于 Synchronized 专门翻阅 JVM HotSpot 1.8 的源码来研究了了,那时候就发现有一个点,一个几乎网上所有文章包括《Java并发编程的艺术》也是这样说的一个点。
锁升级想必网上有太多文章说过了,这里提到当轻...
Synchronized 和 ReentrantLock 有什么区别?回答重点Synchronized 是 Java 内置的关键字,实现基本的同步机制,不支持超时,非公平,不可中断,不支持多条件。
ReentrantLock 是 JUC 类库提供的,由 JDK 1.5 引入,支持设置超时时间,可以避免死锁,比较灵活,并且支持公平锁,可中断,支持多条件判断。
ReentrantLock 需要手...
什么是 Java 中的锁自适应自旋?回答重点锁自适应自旋 是 Java 锁优化中的一种机制,用于减少线程在竞争锁时频繁挂起和恢复的开销。
自适应自旋的核心思想是,在锁争用较少的情况下,线程在进入等待状态前,先执行一段自旋操作(即短暂忙等),而不是立刻挂起线程。
在 Java 中 Syncronized 在争抢重量级锁时候会自旋。具体指的是在重量级锁时,一个线程如果竞争锁失败会进行自旋操作,说...
你使用过 Java 的累加器吗?回答重点在 Java 中累加器(Accumulator)一般指的是LongAdder 和 DoubleAdder 类,它们在高并发场景下比传统的 AtomicLong 更具优势。
LongAdder 和 DoubleAdder
LongAdder:适用于 long 类型的累加操作,提供了高效的累加功能,尤其是在多线程环境中。
DoubleAdder:适用于 d...
当 Java 的 synchronized 升级到重量级锁后,所有线程都释放锁了,此时它还是重量级锁吗?回答重点当重量级锁释放了之后,锁对象是无锁的。
有新的线程来竞争的话又会从轻量级锁开始。
扩展知识我们都知道 synchronized 的锁升级,也听过锁升级之后不会降级,所以理所当然的认为当一个锁升级为重量级锁之后,任何线程再来争抢之后会走重量级锁的逻辑。
不会再从无锁到偏向锁到轻量级锁...
如何优化 Java 中的锁的使用?回答重点主要有以下两种常见的优化方法:
1)减小锁的粒度(使用的时间):
尽量缩小加锁的范围,减少锁的持有时间。即在必要的最小代码块内使用锁,避免对整个方法或过多代码块加锁。
使用更细粒度的锁,比如将一个大对象锁拆分为多个小对象锁,以提高并行度(参考 HashTable 和ConcurrentHashMap 的区别)。
对于读多写少的场景,可以使用读写锁(...
Java 中 ReentrantLock 的实现原理是什么?回答重点ReentrantLock 其实就是基于 AQS 实现的一个可重入锁,支持公平和非公平两种方式。
内部实现依靠一个 state 变量和两个等待队列:同步队列和等待队列。
利用 CAS 修改 state 来争抢锁。
争抢不到则入同步队列等待,同步队列是一个双向链表。
条件 condition 不满足时候则入等待队列等待,是个单...
你了解 Java 中的读写锁吗?回答重点读写锁,它允许多个线程同时读取共享资源,而在写操作时确保只有一个线程能够进行写操作(读读操作不互斥,读写互斥、写写互斥)。这种机制适合于读多写少的场景,因为它提高了系统的并发性和性能。
Java 中的 ReadWriteLock 是通过 ReentrantReadWriteLock 实现的,它提供了以下两种锁模式:
读锁(共享锁):允许多个线程同时获...
说说 AQS 吧?回答重点
如果面试官问你为什么需要 AQS ,不要长篇大论,容易把自己和面试官绕进去。就这样简要的回答:
简单来说 AQS 就是起到了一个抽象、封装的作用,将一些排队、入队、加锁、中断等方法提供出来,便于其他相关 JUC 锁的使用,具体加锁时机、入队时机等都需要实现类自己控制。
它主要通过维护一个共享状态(state)和一个先进先出(FIFO)的等待队列,来管理线程对共...
什么是 Java 的 CAS(Compare-And-Swap)操作?回答重点CAS 是一种硬件级别的原子操作,它比较内存中的某个值是否为预期值,如果是,则更新为新值,否则不做修改。
工作原理:
比较(Compare):CAS 会检查内存中的某个值是否与预期值相等。
交换(Swap):如果相等,则将内存中的值更新为新值。
失败重试:如果不相等,说明有其他线程已经修改了该值,CAS 操作失败...
什么是 Java 内存模型(JMM)?回答重点Java 内存模型(Java Memory Model, JMM) 是 Java 虚拟机 (JVM) 定义的一种规范,用于描述多线程程序中变量(包括实例字段、静态字段和数组元素)如何在内存中存储和传递的规则。规范了线程何时会从主内存中读取数据、何时会把数据写回主内存。
JMM 的核心目标是确保多线程环境下的可见性、有序性和原子性,从而避免由于硬件...
什么是 Java 中的原子性、可见性和有序性?回答重点1)原子性(Atomicity):
原子性指的是一个操作或一系列操作要么全部执行成功,要么全部不执行,期间不会被其他线程干扰。
2)可见性(Visibility):
可见性指的是当一个线程修改了某个共享变量的值,其他线程能够立即看到这个修改。
3)有序性(Ordering):
有序性指的是程序执行的顺序和代码的先后顺序一致。但在多线程环境...
Java 创建线程池有哪些方式?回答重点1)使用 Executors 工厂类,例如Executors.newFixedThreadPool(10);
2)使用 ThreadPoolExecutor 直接创建线程池
1234567ExecutorService threadPool = new ThreadPoolExecutor( 5, // corePoolSize 10, /...
Java 中的线程安全是什么意思?回答重点线程安全是指多个线程访问某一共享资源时,能够保证一致性和正确性,即无论线程如何交替执行,程序都能够产生预期的结果,且不会出现数据竞争或内存冲突。在 Java 中,线程安全的实现通常依赖于同步机制和线程隔离技术。
扩展知识常用的线程安全措施
同步锁:通过 synchronized 关键字或 ReentrantLock 实现对共享资源的同步控制。
原子操...
什么是 Java 的 happens-before 规则?回答重点happens-before 规则是 Java 内存模型 (Java Memory Model, JMM) 中的核心概念,用于定义多线程程序中操作的可见性和顺序性。它通过指定一系列操作之间的顺序关系,确保线程间的操作是有序的,避免由于重排序或线程间数据不可见导致的并发问题。
happens-before 规则的主要规则:1)程...
Java 中的 final 关键字是否能保证变量的可见性?回答重点不可以。
你可能看到一些答案说可以保证可见性,那不是我们常说的可见性。
一般而言我们指的可见性是一个线程修改了共享变量,另一个线程可以立马得知更改,得到最新修改后的值。
而 final 并不能保证这种情况的发生,volatile 才可以。
而有些答案提到的 final 可以保证可见性,其实指的是 final 修饰的字段在构造...
什么是 Java 中的指令重排?回答重点指令重排是 Java 编译器和处理器为了优化性能,在保证单线程程序语义不变的情况下,对指令执行顺序进行调整的过程。在多线程环境下,指令重排可能导致线程之间的操作出现不同步或不可见的现象,因此 Java 提供了内存模型(JMM)和相关机制(如 volatile 和 synchronized)来限制这种行为,确保并发操作的正确性。
主要原因:
编译器优化:...
为什么在 Java 中需要使用 ThreadLocal?回答重点因为在多线程编程中,多个线程可能会同时访问和修改共享变量,导致线程安全问题。ThreadLocal 提供了一种简单的解决方案,使每个线程都有自己的独立变量副本,避免了多线程间的变量共享和竞争,从而解决了线程安全问题。
与通过加锁、同步块等传统方式来保证线程安全相比。ThreadLocal 不需要对变量访问进行同步,减少了上下文切...
Java 中的 ThreadLocal 是如何实现线程资源隔离的?回答重点ThreadLocal 提供了一种线程内独享的变量机制,使每个线程都能有自己独立的变量副本。每个线程内部维护一个 ThreadLocalMap,这个 ThreadLocalMap 用于存储线程独立的变量副本。ThreadLocalMap 以 ThreadLocal 实例作为键,以线程独立的变量副本作为值。不同线程通过 ...
为什么 Java 中的 ThreadLocal 对 key 的引用为弱引用?回答重点使用弱引用作为 ThreadLocal 的键可以防止内存泄漏。若 ThreadLocal 实例被不再需要的线程持有为强引用,那么当该线程结束时,相关的 ThreadLocal 实例及其对应的数据可能无法被回收,导致内存持续占用。
而弱引用允许垃圾回收器在内存不足时回收对象。这样,当没有其他强引用指向某个 Th...
Java 中的 InheritableThreadLocal 是什么?回答重点InheritableThreadLocal 是 ThreadLocal 的一个扩展,用于在线程创建时将父线程的 ThreadLocal 变量副本传递给子线程,使得子线程可以访问父线程中设置的本地变量。它解决了 ThreadLocal 无法在子线程中继承父线程本地变量的问题。
工作原理:
当创建子线程时,Inhe...
Java 中使用 ThreadLocal 的最佳实践是什么?回答重点1)不要滥用 ThreadLocal:
ThreadLocal 适用于需要为每个线程维护独立副本的场景,例如:数据库连接、用户会话、事务上下文、临时缓存等。
对于能通过参数传递的上下文信息,不应该使用 ThreadLocal 来处理,避免设计不合理和代码可读性差的问题。
2)避免内存泄漏:
ThreadLocal 中的...
Java 中 Thread.sleep(0) 的作用是什么?看起来 Thread.sleep(0) 很奇怪,让线程睡眠 0 毫秒?那不是等于没睡眠吗?
是的,确实没有睡眠,但是调用了 Thread.sleep(0) 当前的线程会暂时出让 CPU ,这使得 CPU 的资源短暂的空闲出来别的线程有机会得到 CPU 资源。
所以,在一些大循环场景,如果害怕这段逻辑一直占用 CPU 资源,则可以调用...