基础面试题篇1

前言

今天很晚了,就用手机编辑吧,持之以恒。前文介绍了jvm和线程,本文将介绍一些java基础相关。

基础面试题篇1

  1. jdk8中HashMap的底层实现

基础结构:使用数组和链表的结构。每个数组元素(bucket)都包含一个链表,用于存储具有相同哈希值的键值对。
红黑树:当链表长度超过一定阈值(默认为8)时,链表会转换为红黑树,以提高查找效率。红黑树是一种自平衡的二叉查找树,可以在对数时间内完成查找操作。
分段锁:为了解决多线程下的性能问题,引入了 Segment 概念,每个 Segment 是一个锁,多个 Segment 可以共享同一个锁。通过这种方式,提高了并发性能。
哈希函数:使用了一种基于除法和加权的哈希函数,以提高哈希分布的均匀性,减少哈希冲突。
动态调整:支持动态调整大小。当哈希表的使用率超过一定阈值(默认为0.75)时,会触发扩容操作。扩容时,会将数组大小翻倍。
加载因子:使用了一个默认的加载因子(0.75),它决定了哈希表的空间使用情况。加载因子越高,空间利用率越高,但查找性能可能会降低。

  1. Integer的底层缓存

Integer 类的底层缓存是指 IntegerCache。它是为了提供一种优化机制,避免频繁地创建和销毁 Integer 对象而设计的。
IntegerCache 是一个范围在 -128 到 127 之间的缓存池,用于存储 Integer 对象。当我们在代码中直接使用数字字面量时,例如 Integer i = 127;,Java 会首先检查 IntegerCache 中是否有可用的对象,如果有,则直接返回该对象,而不是创建一个新的对象。这样可以减少对象创建和垃圾回收的开销,提高性能。
当我们在代码中使用的数字字面量超出了 IntegerCache 的范围时,Java 会创建一个新的 Integer 对象。例如,使用大于 127 或小于 -128 的数字字面量时,会创建新的 Integer 对象。
需要注意的是,IntegerCache 只适用于直接使用数字字面量的场景。如果使用其他方式创建 Integer 对象,例如通过调用 Integer 类的静态方法 valueOf() 或 new Integer(),则不会利用 IntegerCache 的优化机制。
说明:缓存范围可通过jvm参数调整。

  1. 重量级对象BigDecimal

BigDecimal 在 Java 中被设计为重量级对象(heavyweight object),这是因为 BigDecimal 对象包含了一个数值和一个 scale(小数点后的位数)。为了支持这些额外的信息,BigDecimal 对象需要更多的内存和计算资源,因此它们的创建和操作通常比轻量级对象(如基本数据类型或包装类)更耗费资源。
另外,BigDecimal 的设计初衷是为了进行高精度的浮点数运算,特别是涉及到金融和货币计算的场景。在这些场景中,精度和稳定性是非常重要的,因此 BigDecimal 提供了更高精度的计算能力,同时也需要更多的资源来支持这种能力。
为了减少创建 BigDecimal 对象的开销,可以考虑重用已经创建的对象,而不是频繁地创建新的对象。例如,可以将常用的 BigDecimal 值存储在变量中,并在需要时重复使用这些变量,而不是每次都创建新的 BigDecimal 对象。此外,还可以使用 BigDecimal 的子类,如 BigInteger 和 BigDecimal 的某些静态方法(如 valueOf())来创建对象,这些方法可能会使用缓存机制来减少对象创建的开销。

  1. 介绍一下阻塞队列

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空;当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
以下是几种实现:
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

  1. 介绍一下线程池的提交和执行流程

创建线程池对象:首先需要创建一个线程池对象,可以通过调用 ThreadPoolExecutor 类或其他线程池实现类的构造方法来完成。线程池的创建可以根据需要进行参数配置,例如核心线程数、最大线程数、任务队列类型等。
提交任务:使用线程池对象的 submit() 或 execute() 方法来提交任务。这些方法接受一个 Runnable 或 Callable 对象作为参数,这些对象代表要执行的任务。当任务被提交后,线程池会将其放入任务队列中等待执行。
任务排队与调度:线程池会根据配置的策略将新提交的任务放入任务队列中。当线程池中的线程数量小于核心线程数时,线程池会创建新的线程来执行任务;当线程数达到核心线程数后,新任务会被放入任务队列中等待执行。如果任务队列已满,线程池会根据配置的最大线程数创建新的线程来处理任务。
任务执行:当线程池中的某个线程从任务队列中取出任务后,会开始执行该任务。任务的执行方式是异步的,不会阻塞提交任务的线程。任务的执行逻辑由 Runnable 或 Callable 对象的 run() 或 call() 方法定义。
任务完成与返回结果:当任务执行完成后,线程池会根据需要返回结果给提交任务的线程。如果提交的是 Callable 对象,可以使用 Future 对象来获取任务的返回值。如果提交的是 Runnable 对象,则无法获取任务的返回值。
需要注意的是,如果提交的任务是计时器任务或者定时任务,那么它们通常会使用 ScheduledThreadPoolExecutor 类来处理,而不是普通的 ThreadPoolExecutor 类。此外,在使用线程池时需要注意合理配置线程池的参数,避免资源浪费或性能瓶颈。
Spring中还有ThreadPoolTaskExecutor。

  1. 介绍一下CountDownLatch和CyclicBarrier

CountDownLatch 是一个同步辅助类,允许一个或多个线程等待其他线程完成操作。它有一个计数器,初始值为一个正整数,每次调用 countDown() 方法计数器减一,当计数器达到零时,所有等待的线程被唤醒并继续执行。CountDownLatch 常用于多线程并发执行的场景,其中一些线程需要等待其他线程完成某个阶段的工作后才能继续执行。
CyclicBarrier 是一个同步工具类,允许一组线程互相等待,直到所有线程都到达某个屏障点(barrier point)再一同继续执行。每个 CyclicBarrier 实例都有一个屏障(barrier),当一个线程到达屏障点时,它会等待其他线程也到达屏障点,然后所有线程一同继续执行。CyclicBarrier 通常用于多线程并发测试、多线程数据同步等场景。
简单来说,CountDownLatch 用于让一组线程等待某个条件成立后再继续执行,而 CyclicBarrier 用于让一组线程在某个点上同步执行。

太晚了,今天就先到这里吧,明天见。

你可能感兴趣的:(面试合集,java,数据结构)