java知识点
一、ArrayList 的扩容
1.ArrayList 的扩容机制是将新容量计算为原容量的 15倍,即 oldcapacity+(oldcapacity >>1)。这个操作将新容量设置为当前容量的 1.5 倍。
2.在 ArrayList 扩容时,会使用 Arrays.copyof()方法来复制原数组中的元素到新数组中,完成数组的扩容操作。
当 ArrayList 中的元素数量超过其当前容量时,会触发扩容机制。默认情况下,ArrayList 的初始容量为 10。
当发生扩容时,Arraylist 会创建一个新的数组,其容量为原数组的15倍(即 oldcapacity +(oldcapacity >>1)),然后将原数组中的元素复制到新数组中,复制过程是通过 Arrays.copyof()方法实现的。
arraylist底层是动态数组,当数组元素超过当前数组容量时会创建新的数组,扩容至原来的1.5倍 再把原来的数组用copyof()复制过去再添加新元素
arraylist初始化后长度为0 添加元素,调用add()时默认初始容量是10
ensurecapcity()判断是否需要扩容,copyof0)复制数组
二、线程池原理
Java 并发库中提供了5种常见的线程池实现,主要通过 Executors 工具类来创建。
1)FixedThreadPool:创建一个固定数量的线程池。
线程池中的线程数是固定的,空闲的线程会被复用。如果所有线程都在忙,则新任务会放入队列中等待。
适合负载稳定的场景,任务数量确定且不需要动态调整线程数。
2)CachedThreadPool:一个可以根据需要创建新线程的线程池。
线程池的线程数量没有上限,空闲线程会在 60 秒后被回收,如果有新任务且没有可用线程,会创建新线程。
适合短期大量并发任务的场景,任务执行时间短目线程数需求变化较大,
3)SingleThreadExecutor:创建一个只有单个线程的线程池
只有一个线程处理任务,任务会按照提交顺序依次执行。
适用于需要保证任务按顺序执行的场景,或者不需要并发处理任务的情况。
4)ScheduledThreadPool:支持定时任务和周期性任务的线程池,
可以定时或以固定频率执行任务,线程池大小可以由用户指走。
适用于需要周期性任务执行的场景,如定时任务调度器,
5)WorkStealingPool:基于任务窃取算法的线程池,线程池中的每个线程维护一个双端队列(deque),线程可以从自己的队列中取任务执行。如果线程的任务队列为空,它可以从其他线程的队列中“窃取”任务来执行,达到负载均衡的效
果。适合大量小任务并行执行,特别是递归算法或大任务分解成小任务的场景。
“Terminated” 状态表示线程已经完全执行结束或者因为异常退出,线程的生命周期就此终止。
corePoolSize 参数表示核心线程数,即线程池中始终保持的线程数量。该数量的线程在没有任务时也不会被销毁。
SynchronousQueue 不存储任务,而是直接将任务提交给线程,如果没有可用线程执行任务,则会阻塞任务的提交。
默认情况下,线程池不会预先创建核心线程。在任务提交之后才会创建线程。不过,可以通过 setPrestartAllCoreThreads 将其改为 true 来预先创建核心线程。
三、如何合理的设置java线程池的线程数
CPU 密集型任务
CPU 密集型任务,就好比单纯的数学计算任务,它不会涉及 I/0 操作,也就是说它可以充分利用 CPU 资源(如果涉及 I/O,在进行 I/0 的时候 CPU 是空闲的),不会因为 I/0 操作被阻塞,因此不需要很多线程,线程多了上下文开销反而会变多。
根据经验法则,CPU 密集型任务线程数=CPU核心数+1。
I/0 密集型任务
I/0 密集型任务,有很多 I/0 操作,例如文件的读取、数据库的读取等等,任务在读取这些数据的时候,是无法利用 CPU
的,对应的线程会被阻塞等待 I/0 读取完成,因此如果任务比较多,就需要有更多的线程来执行任务,来提高等待 !/0 时候
的 CPU 利用率。
根据经验法则,I/0 密集型任务线程数=CPU核心数*2或更多一些
(这句话一定要和面试官说)以上公式仅是一个纯理论值,仅供参考!在生产上,需要考虑机器的硬件配置,设置预期的CPU 利用率、CPU负载等因素,再通过实际的测试不断调整得到合理的线程池配置参数。
如果线程空闲时间超过空闲存活时间,并且当前线程数大于核心线程数,则会按照配置逐步销毁多余的线程,直到线程数等于核心线程数。这是为了减少资源消耗。
对于 CPU 密集型任务,为了充分利用 CPU 资源并减少上下文切换的开销,经验法则是设置线程数为 CPU 核心数 + 1。
对于 I/O 密集型任务,因为涉及大量的 I/O 操作造成线程会在等待 I/O 阻塞,因此可以增加线程数来提高 CPU 利用率,经验法则是设置线程数为 CPU 核心数 * 2。
四、java集合
Vector 是 Java 集合框架中的一个动态数组实现,它是线程安全的。ArrayList 和 LinkedList 不保证线程安全,而 HashSet 属于 Set 接口的实现类,与动态数组无关。
LinkedList 可以实现 Queue 接口中的 FIFO(先进先出)操作。HashSet 和 TreeSet 属于 Set 接口的实现,不保证顺序,而 ArrayList 是基于索引的动态数组,不适用于队列操作。
ConcurrentHashMap 是 Java 集合框架中提供的线程安全的哈希表,实现了对高并发环境的优化。HashMap、LinkedHashMap 和 TreeMap 都不是线程安全的。