1、谈一谈Java的集合
主要有Collection 和Map两类,Collection接口的实现子类是单列集合,Map的是双列集合。Collection 接口下面有两个子接口,List和Set。List有两个实现类ArrayList和LinkedList。ArrayList的底层实现是动态数组,LinkedList的底层是双向链表。
2、面试官继续问:这两个有什么特点,或者说异同点吗?
ArrayList查找的效率高,因为数组根据下标查找时间复杂度是O(1),但是插入删除效率低,因为插入时需要把插入位置之后的元素往后挪。LinkedList插入和删除的效率高,但是查找的效率不高,因为它是链表,需要顺着元素一个一个往下找。总结来说一个适合读多写少的场景,另一个适合写多读少的场景。
3、HashMap也讲一下
在JDK1.7中,HashMap的底层实现是数组+链表,以put操作为例说一下原理,首先根据key计算hash值,然后hash值对数组长度取余数,确定它要放的位置,假设是table[i],如果table[i]是空的,那就直接新增,不为空就顺着链表往下找(table[i]相当于链表表头),如果发现key相同的就更新它,没有相同的就把key,value封装成一个node节点加入到链表后面。这有一个缺点就是在链表过长的时候效率变低,所以在jdk1.8的时候,底层实现是数组+链表+红黑树,当链表长度超过阈值的时候它就变为红黑树。然后HashMap也是线程不安全的,如果要保证线程安全可以使用ConcurrentHashMap。
4、什么情况下会有线程安全问题
5、线程和进程有什么区别
本质区别:进程是操作系统资源分配的基本单位,线程是任务调度和执行的基本单位。
在开销方面:每个进程都有独立的代码和数据空间,程序之间的切换会有较大的开销;线程可以看作轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器
稳定性方面:进程中每个线程如果崩溃了,可能导致整个进程崩溃。而一个进程的崩溃不会影响其他进程。
包含关系来看:没有线程的进程可以看作单线程的,一个线程可以有多个线程。
6、线程之间的通信方式,进程之间的通信方式
线程之间通信:volatile、等待/通知机制、join 方式、InheritableThreadLocal、MappedByteBuffer
进程间的通信比较复杂:
- 信号量:信号量是一个计数器,用于多进程对共享数据的访问,解决同步相关的问题并避免竞争条件
- 共享存储:多个进程可以访问同一块内存空间,需要使用信号量用来同步对共享存储的访问
- 管道通信:管道是用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件 pipe 文件,该文件同一时间只允许一个进程访问,所以只支持半双工通信
- 匿名管道(Pipes):用于具有亲缘关系的父子进程间或者兄弟进程之间的通信
- 命名管道(Names Pipes):以磁盘文件的方式存在,可以实现本机任意两个进程通信,遵循 FIFO
- 消息队列:内核中存储消息的链表,由消息队列标识符标识,能在不同进程之间提供全双工通信,对比管道:
- 匿名管道存在于内存中的文件;命名管道存在于实际的磁盘介质或者文件系统;消息队列存放在内核中,只有在内核重启(操作系统重启)或者显示地删除一个消息队列时,该消息队列才被真正删除
- 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收
不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
- 套接字:与其它通信机制不同的是,可用于不同机器间的互相通信
7、RabbitMQ使用的是哪种通信方式
8、堆内存和栈内存,数据结构中的堆和栈。
8、讲一下spring的aop
9、讲一下java的反射机制,你在项目中使用过反射吗,你看过框架中反射相关的源码吗?
10、有一个文件,里面存了1千万个整数,主机的内存只有1.5MB,磁盘没有限制,你要对这1千万个整数排序,你会怎么做?
11、讲一下jvm中的垃圾回收机制。
12、缓存穿透、缓存雪崩是什么问题,一般怎么解决。
13、讲一下MySQL中的索引。事务。你的项目中有使用到事务吗?