21. JVM是如何处理异常(大概流程)?
如果发生异常,方法会创建一个异常对象(包括:异常名称、异常描述以及异常发生时应用程序的状态),并转交给JVM。创建异常对象,并转交给JVM的过程称为抛出异常。
异常发生后,可能有一系列的方法调用,终才进入抛出异常的方法,这一系列方法调用的有序列表叫做调用栈。
JVM会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。如果没有,JVM就会将该异常转交给默认的异常处理器(默认处理器为JVM 的一部分),默认异常处理器打印出异常信息并终止应用程序。
22. 请聊一下java的集合类,以及在实际项目中你是如何用的?
- 注意说出集合体系、常用类、接口、实现类。
- 高并发的集合类、参照集合增强内容。
- 在实际项目中引用。
23. Java集合框架类图:
24. ArrayList与LinkedList的区别?
- ArrayList基于动态数组(顺序表)的数据结构,LinkedList基于链表(双向链表)的数据结构;
- ArrayList随机访问快,LinkedList随机访问慢;
- ArrayList添加和删除慢,LinkedList添加和删除快;
- 此外,LinkedList还专门提供了操作表头和表尾元素的方法,可当做堆栈、队列和双向队列使用。
25. ArrayList与Vector的区别?
- 相同:底层都是数组实现的;
- ArrayList不是线程安全,但是效率高,Vector是线程安全,效率低(源码中方法用synchronized修饰);
- ArrayList和Vector都采用线性连续存储空间,默认容量大小都为10;存储空间不足时,ArrayList默认1.5倍扩容 ,Vector默认1倍扩容;
- ArrayList可以通过Collections.synchronizedList(List list) 实现线程同步的集合。
- 注:Vector是java的遗留框架,遗留框架设计上存在问题,已经不再使用。遗留框架还有Hashtable、Dictionary、BitSet、Stack、Properties、Enumeration。
26. HashMap和Hashtable的区别?
- HashMap是非同步,非安全线程,但速度快;Hashtable是同步,安全线程,但速度慢。
- HashMap可以接受null值( key和value都可为空);Hashtable不可以。
- HashMap默认容量大小是16;Hashtable默认容量大小是11。
- HashMap的hash值重新计算过,Hashtable直接使用hashCode。
- HashMap继承自AbstractMap类,Hashtable继承自Dictionary类
27. HashMap在1.8中做了哪些优化?
- 数据结构 --> 数组 + 链表 + 红黑树
- hash函数 --> 高16参与Hash,降低Hash冲突
- 扩容优化 --> 扩容时元素不需要进行重新计算位置。新位置 = 原位置 + 原数组长度
28. HashMap线程安全的方式?
HashMap不是线程安全的。
- 方法一:通过Collections.synchronizedMap()
- 方法二:使用ConcurrentHashMap
29. HashMap为什么扩容是两倍?
- 将取模转为位运算操作,提高运算效率,只有2的幂次方成立 -> (n-1)&hash
- 并且在容量是2的幂次方时,n-1的二进制会全为1,位运算时可以充分散列,避免不必要的哈希冲突。
30. HashMap为什么要使用红黑树?
- 红黑树是动态平衡的一棵二叉查找树,可以加速查找。
- HashMap什么时候转换红黑树(数组长度大于64,索引节点位置元素个数大于8转换)、什么时候转换链表(索引位置元素个数等于6时转换)。
- 说一下向关联的知识。
31. HashMap为什么用红黑树不用普通的AVL树?
总:
AVL是高度平衡树,调整频率高,适合查询多,修改少的场景。红黑树是弱平衡树,调整频率低,适合修改多场景。
AVL树:
AVL树是高度平衡树,任何两个左右子树高度大于1时,就好动态调整到平衡。所以AVL树适合用于插入与删除次数比较少,但查找多的情况。
红黑树:
它也是一种平衡二叉树,但每个节点带颜色,可以是红或黑。通过对任何一条从根到叶子的路径上各个节点颜色的限制,确保没有一条路径会比其它路径长出两倍,所以红黑树是一种弱平衡二叉树。红黑树从根到叶子的最长路径不会超过最短路径的2倍。
32. HashMap为什么在JDK 1.8之后不再有死循环的问题?
JDK1.8以前,导致死循环的主要原因是扩容后,节点的顺序会反掉,可能会形成一个环形链。
原因:两个线程同时调用了扩容方法,扩容同一索引位置。线程一执行途中被挂起(Entry next = e.next;),线程二获得执行时间,执行完扩容操作,线程一再次获得执行时间,会形成环形链,然后调用HashTable.get()时,出现了无限循环。
https://blog.csdn.net/huantai3334/article/details/104170984
33. 解决hash冲突的方式有哪些?
- 开放定址法 --> ThreadLocal
- 链地址法 --> HashMap
- 再哈希法(又叫双哈希):当发生冲突时,重新计算哈希计算地址,直到无冲突。会增加计算时间。
- 建立公共溢出区:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
34.Queue接口:
单端队列与双端队列:
- Queue与Deque
阻塞队列与非阻塞队列:
- 阻塞队列:(说一下箭头后的装逼知识)
- ArrayBlockingQueue ->有边界;底层数组;不支持同时读写,底层用一把锁(ReentrantLock)
- LinkedBlockingQueue ->可选择的有边界;支持同时读写,底层两把锁
- PriorityBlockingQueue -> 底层数据结构是堆 -> 数组与堆的转换:heapInsert(插入堆)、heapify(堆化)
- DelayQueue -> 单机版延迟队列;添加元素实现Delay接口,重写两个方法。
- SynchronousQueue -> 容量为0,put()添加一个元素后,会等待task()删除一个元素
- LinkedBlockingDeque。
- 非阻塞队列:PriorityQueue、ConcurrentLinkedQueue、LinkedTransferQueue。
队列方法:(@&@)
35. 集合类是怎么解决高并发中的问题?
- 先说一下,非安全的集合类。
- 然后再说,普通的安全的集合类(Vector HashTable)。
- 最后说,JUC下的高并发集合类。
- ConcurrentHashMap和底层 -> ConcurrentHashMap和HashTable的区别(拓展点)。
- ConcurrentSkipListMap(Set):线程安全的有序的哈希表,它替代TreeMap。
- CopyOnWriteArrayList:写入时,加锁将原数据复制到另一个数组中,它只能保证数据的最终一致性,不适合频繁写入的操作。
36. JDK1.8的新特性?
- Lambda表达式。
- 函数式编程:Optional、Predicate、Supplier、Consumer、Function。
- 方法引用和构造器调用 --> :: 关键字来传递方法或者构造函数引用。
- 接口中可以有默认方法:default关键字。
- Stream API。
- 新时间日期API。
- CompletableFuture类。
37. Stream的并行操作原理?Stream并行的线程池是从哪里来的?
Stream的概念:
Stream专注于对容器对象进行各种非常便利、高效的聚合操作或者大批量数据操作。
三个操作步骤:
- 创建Stream:从一个数据源,如集合、数组中获取流。
- 中间操作:一个操作的中间链,对数据源的数据进行操作。
- 终止操作:一个终止操作,执行中间操作链,并产生结果。
Stream并行(parallel)原理:
它底层依赖于ForkJoinPool.commonPool线程池,这是一个JVM进程全局共享的线程。在ForkJoin上进行了一层封装,将Stream不断尝试分解成更小的集合,然后使用ForkJoin框架分而治之。
38. 关于intern() pass
String a=new String("123")+new String("456"); // String b=new String("123456"); String intern = a.intern(); System.out.println(intern==a); // 注释输出true,取消注释 输出false
参考文章(不错):
https://blog.csdn.net/qq_41884976/article/details/83353389
39. Java种的代理有几种实现方式?
静态代理:
在程序编译前,代理类已经被创建完成。
动态代理:
- JDK:Proxy
- 面向接口的动态代理:代理一个对象去增强面向某个接口中定义的方法。
- 没有接口不可用。
- 只能读取到接口上的一些注解。
- 举例:MyBatis DeptMapper dm=sqlSession.getMapper(DeptMapper.class)
- 第三方:CGlib
- 面向父类的动态代理(继承)-> 底层原理:操作字节码生成新的类 -> 大量使用可能导致元空间的溢出(拓展点)
- 有没有接口都可以使用。
- 可以读取类上的注解。
- 举例: AOP 日志 性能检测 事务
40. Java中的自增是线程安全的吗,如何实现线程安全的自增?
- i++、++i 不是线程安全的。
- 解决1:增加Synchronized进行线程同步。
- 解决2:使用Reetrantent锁进行锁定(lock、unlock处理)。
- 解决3:AtomicInteger -> 使用Unsafe中的CAS -> CAS的ABA问题。