《揭秘互联网大厂 Java 求职者面试:硬核技术大考验》

62 阅读6分钟

《揭秘互联网大厂 Java 求职者面试:硬核技术大考验》

场景: 在一间明亮的会议室里,面试官一脸严肃地坐在桌前,面前摆放着一摞简历。门外,水货程序员王铁牛神色忐忑地等待着面试开始。

第一轮: 面试官(眼神锐利):“说说 Java 核心知识中关于类和对象的基本概念。” 王铁牛(面露思索):“嗯,类就像是一个模板,对象是根据类创建出来的具体实例,就像汽车的图纸和实际的汽车那样。” 面试官(微微颔首):“不错。那接着,讲讲 JUC(Java 并发包)中常用的线程安全集合有哪些。” 王铁牛(挠挠头):“呃,好像有 ConcurrentHashMap 吧。” 面试官(露出不耐):“那你说说它和普通 HashMap 在线程安全方面的区别。” 王铁牛(支支吾吾):“这个……不太清楚。”

第二轮: 面试官(眉头微皱):“那我们来谈谈 JVM(Java 虚拟机),你知道 JVM 内存结构是怎样的吗?” 王铁牛(眼神慌乱):“大概知道有栈、堆这些,具体不太清楚。” 面试官(加重语气):“那堆内存中新生代和老年代分别存储什么。” 王铁牛(迟疑片刻):“新生代好像存新创建的对象,老年代存久一点的对象吧。” 面试官(冷哼一声):“那你说说在什么情况下会触发 Minor GC 和 Major GC。” 王铁牛(一脸茫然):“不太懂。”

第三轮: 面试官(一脸严肃):“现在说说多线程相关的,线程池的作用是什么。” 王铁牛(眼神闪躲):“好像是能复用线程吧。” 面试官(眼神锐利):“那你说说线程池的核心参数有哪些。” 王铁牛(磕磕绊绊):“有核心线程数、最大线程数这些吧。” 面试官(加重语气):“那你说说当线程池中的任务过多时,会有什么情况发生。” 王铁牛(慌乱不已):“不太清楚,可能会出错吧。”

面试结束总结: 面试官(缓缓说道):“从你这三轮的表现来看,对这些核心技术掌握得很不扎实,很多基本概念和原理都不清楚,回去等通知吧,我们会综合考虑再做决定。”

问题答案详解:

Java 核心知识中类和对象:

  • :是对一类事物的抽象描述,它定义了该类对象所共有的属性和方法。例如定义一个“汽车”类,可能有颜色、型号、速度等属性,以及启动、刹车等方法。
  • 对象:是根据类创建出来的具体实例,每个对象都拥有类中定义的属性和方法的具体值。比如通过“汽车”类创建出具体的某辆汽车对象,这辆汽车有特定的颜色、型号和速度等。

JUC 中常用的线程安全集合:

  • ConcurrentHashMap:它是线程安全的哈希表,在多线程环境下能够保证并发读写的安全性。与普通 HashMap 不同,普通 HashMap 在多线程并发修改时可能会出现数据不一致的问题,而 ConcurrentHashMap 通过分段锁等机制来保证线程安全。在插入、删除、查询等操作时,ConcurrentHashMap 能够有效地避免数据竞争和数据不一致的情况。
  • 其他线程安全集合还有:CopyOnWriteArrayList,在进行遍历操作时,不会阻塞写操作,适合读多写少的场景;ConcurrentSkipListMap,基于跳表数据结构实现,支持高效的并发插入、删除和查找操作。

JVM 内存结构:

  • JVM 内存结构主要分为堆、栈、方法区、程序计数器等。
    • :是 JVM 中最大的一块内存区域,主要用于存储对象实例。堆内存又分为新生代和老年代。
      • 新生代:用于存放新创建的对象,分为 Eden 区和两个 Survivor 区(From Survivor 和 To Survivor),大部分对象在新生代的 Eden 区创建,经过一定的垃圾回收周期后,如果对象还存活,就会被移动到 Survivor 区,经过多次复制后,仍然存活的对象会被晋升到老年代。
      • 老年代:主要存放经过多次垃圾回收仍然存活的对象,以及大对象(如超过一定阈值的对象)。
    • :用于存储局部变量、方法调用栈帧等,每个线程都有自己独立的栈空间,栈内存的生命周期与线程相同,当线程结束时,栈内存自动释放。
    • 方法区:存储类的信息、常量、静态变量等,类似于共享的全局存储区域。
    • 程序计数器:每个线程都有一个程序计数器,用于记录当前线程执行的字节码指令地址,是线程私有的,线程切换时,程序计数器会恢复到之前保存的指令地址继续执行。

Minor GC(新生代垃圾回收)和 Major GC(老年代垃圾回收)触发条件:

  • Minor GC:当新生代中的 Eden 区满了的时候,就会触发 Minor GC,清理新生代中的垃圾对象,将存活的对象复制到 Survivor 区,或者晋升到老年代。
  • Major GC:当老年代空间不足或者需要进行 Major GC 来压缩老年代空间时触发。比如老年代中的对象过多、大对象无法在新生代分配等情况,就会触发 Major GC。

线程池的作用及核心参数:

  • 线程池的作用:
    • 复用线程:避免频繁创建和销毁线程带来的性能开销,当有新的任务到来时,可以从线程池中获取空闲的线程来执行任务,提高线程的利用率。
    • 控制并发数量:可以根据系统的负载和资源情况,合理地控制同时运行的线程数量,避免因过多线程导致系统资源耗尽。
  • 核心参数:
    • 核心线程数:线程池中始终保持的线程数量,即使这些线程处于空闲状态也不会被销毁,当新任务到来时,首先会尝试从核心线程中获取线程来执行任务。
    • 最大线程数:线程池中允许存在的最大线程数量,当线程数量达到核心线程数后,新任务会根据一定的策略创建新的线程,直到线程数量达到最大线程数。
    • 任务队列:用于存放等待执行的任务,当线程池中线程数量已满(达到最大线程数)时,新任务会放入任务队列中等待线程空闲时执行。常见的任务队列有数组队列、链表队列等。
    • 存活时间:当线程空闲一定时间后,如果线程池中的线程数量超过核心线程数,这些空闲线程会被回收,回收的条件包括线程空闲时间超过存活时间。

通过这些技术点的讲解,希望能帮助求职者更好地理解 Java 相关的核心技术。