参考面经:拼多多|客户端开发|秋招|面经【2轮技术+1轮HR面】|2021
————————————————————————————————————————————————————
【第一题】java线程池
参考链接:Java中的线程池
线程池是什么?
在多线程环境下,由于主线程的诸多限制,一些像网络请求等一些耗时的操作必须在子线程中运行,待子线程操作完成后通过Handler切换到主线程中运行,此时无法管理所创建的子线程,并且子线程之间的相互竞争很可能由于占用过多资源而导致死机或者OOM,所以建立了线程池来管理我们所创建的线程。
线程池的好处:
总结就是:减少线程产生的性能开销、避免大量线程之间抢占资源导致阻塞、提供操作线程的功能。(有点像学校管理学生)
1、重用线程池中已存在的线程,减少了线程的创建和消亡多造成的性能开销;
2. 能够有效控制最大的并发线程数,提高了系统资源的使用率,并且还能够避免大量线程之间因为相互抢占系统资源而导致阻塞。
3. 能够对线程进行简单管理,并提供定时执行、定期执行、单线程、并发数控制等功能。
创建一个线程池:ThreadPoolExecutor(参数)
public ThreadPoolExecutor(int corePoolSize, //线程池中的核心线程数
int maximumPoolSize, //线程池最大容纳的线程数
long keepAliveTime, //非核心线程的超时时长,闲置时间超过就会被回收
TimeUnit unit,//超时时长的时间单位
BlockingQueue<Runnable> workQueue, //线程池中保存等待执行的任务的阻塞队列
ThreadFactory threadFactory, //为线程池提供新线程的创建
RejectedExecutionHandler handler)
**关闭线程池:**将线程池的状态改为SHUTDOWN。(遍历线程池中所有的线程,然后依次调用线程的interrupt方法来中断线程)
四种线程池:
1、newFixedThreadPool 我们可以通过Executors中的newFixedThreadPool方法来创建,该线程池是一种线程数量固定的线程池。在这个线程池中所容纳最大的线程数就是我们设置的核心线程数。
2、newCachedThreadPool 核心线程数为0,最大线程数为Integer.MAX_VALUE。该线程池中的线程超时时长为60秒,所以当线程处于闲置状态超过60秒的时候便会被回收。
3、newScheduledThreadPool 它的核心线程数是固定的,对于非核心线程几乎可以说是没有限制的,并且当非核心线程处于限制状态的时候就会立即被回收。
4、newSingleThreadExecutor 在这个线程池中只有一个核心线程,对于任务队列没有大小限制,也就意味着这一个任务处于活动状态时,其他任务都会在任务队列中排队等候依次执行。在执行期间,不需要处理线程同步的问题。
【第二题】数组和链表的区别
总结:
1、存取方式上,数组可以顺序存取或者随机存取,但链表只能顺序存取;
**2、存储位置上,**数组的数据逻辑上和物理存储位置上都相邻,而链表不一定;
3、存储空间上,链表带有指针域,存储密度不如数组;
4、访问查找上,数组可以按照下标随机访问,而链表不支持;当数组元素有序时,按照值查找可用二分查找将复杂度降为logn;
5、操作上,链表插入删除方便,数组则按照实际情况移动数据;
6、空间分配方面,数组在静态存储分配情形下,存储元素数量受限制,动态存储分配情形下,存储空间可以扩充,但需要移动大量元素,导致操作效率低,且如果没有相应的连续存储空间,则会分配失败;而链表只要内存有空间即可分配,且申请即分配。
【第三题】HashMap 的底层实现机制
参考链接:HashMap底层实现和原理(源码解析)
特点:
1、允许null键和null值(HashMap以null作为key时,总是存储在table数组的第一个节点上);
2、不能保证放入元素的顺序;
3、线程不安全(在多线程环境下需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合)。
实现:
使用的是数组和链表来实现对数据的存储;(在JDK1.8中是采用数组+链表+红黑树实现,当链表长度大于8时转换为红黑树)
采用Entry数组存储K-V对,每个键值对组成一个Entry实体,Entry实体实际上是一个单向的链表结构,具有next指针,可以连接下一个Entry实体(解决hash冲突);
【第四题】ArrayList 的底层实现机制
ArrayList的底层数据结构就是一个数组,数组元素类型为Object,对ArrayList的所有操作底层都是基于数组的。
因为对ArrayList添加元素的操作是分为两步的:先放置元素,然后将size的值+1.因此在多线程环境下不能保证原子性以及线程安全。
如何保证线程安全? 1、使用synchronized关键字;2、调用Collections类中的静态方法synchronizedList(),对ArrayList进行调用即可。
ArrayList的主要成员变量:
1、默认容量:10;
2、当显示指出数组长度为0时,将空对象数组赋给elementData数组;
3、当没有显示指出数组长度,使用默认对象数组为DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
4、ArrayList的底层数据结构是一个对象数组,用于存放实际元素,并且被标记为transient,在序列化的时候此字段是不会被序列化的。
5、实际存放的元素的个数,默认时为0个元素;
6、对象数组的最大数组容量为Integer.MAX_VALUE-8
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// 版本号
private static