《互联网大厂Java面试:核心知识大考验》

45 阅读4分钟

互联网大厂Java面试:核心知识大考验

面试官:请简要介绍一下Java中的多线程。

王铁牛:多线程就是多个线程同时执行嘛。在Java里可以通过继承Thread类或者实现Runnable接口来创建线程。

面试官:那如何确保多线程之间的安全呢?

王铁牛:可以用synchronized关键字,它能保证同一时刻只有一个线程访问被修饰的代码块或方法。

面试官:讲得不错。那再说说线程池吧,在什么场景下会用到线程池?

王铁牛:当有大量并发任务时,使用线程池可以避免频繁创建和销毁线程,提高性能。

第一轮提问结束。

面试官:谈谈JVM的内存模型。

王铁牛:JVM内存模型包括堆、栈、方法区等。堆是存放对象实例的地方,栈是存放局部变量等,方法区存class文件结构等。

面试官:那类加载机制是怎样的?

王铁牛:类加载机制有加载、验证、准备、解析、初始化这几个阶段。

面试官:垃圾回收算法有哪些?

王铁牛:有标记清除算法、标记整理算法、复制算法等。

第二轮提问结束。

面试官:请说一下HashMap的底层实现。

王铁牛:HashMap底层是数组加链表再加红黑树。当链表长度超过一定阈值就会转成红黑树。

面试官:那HashMap在多线程环境下会有什么问题?

王铁牛:可能会出现数据丢失、死循环等问题。

面试官:如何解决HashMap在多线程环境下的问题?

王铁牛:可以用ConcurrentHashMap,它是线程安全的。

第三轮提问结束。

面试官:今天的面试就到这里,回去等通知吧。

答案:

多线程:

  • 多线程是指程序中包含多个执行单元,这些执行单元可以并发执行。在Java中,创建线程有两种常见方式:继承Thread类和实现Runnable接口。继承Thread类时,子类重写run方法定义线程执行逻辑;实现Runnable接口时,实现类实现run方法。
  • 确保多线程安全的方式之一是使用synchronized关键字。synchronized可以修饰代码块或方法,当一个线程访问被synchronized修饰的代码块或方法时,其他线程需要等待该线程执行完毕释放锁后才能访问。

线程池:

  • 线程池适用于有大量并发任务的场景。当有大量任务需要处理时,如果频繁创建和销毁线程会消耗大量系统资源,降低性能。使用线程池可以预先创建一定数量的线程,任务提交时从线程池中获取线程执行,执行完后线程不会销毁而是放回线程池,等待下一个任务,从而提高系统的整体性能和响应速度。

JVM内存模型:

  • 堆:是JVM中最大的一块内存区域,用于存放对象实例。
  • 栈:主要存放局部变量、方法调用等信息。每个线程都有自己独立的栈空间。
  • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量等数据。

类加载机制:

  • 加载:将类的字节码文件加载到内存中。
  • 验证:检查加载的字节码文件是否符合JVM规范。
  • 准备:为类的静态变量分配内存并设置初始值。
  • 解析:将符号引用转换为直接引用。
  • 初始化:执行类的静态代码块和为静态变量赋值。

垃圾回收算法:

  • 标记清除算法:先标记出所有需要回收的对象,然后统一回收。
  • 标记整理算法:标记出存活对象后,将存活对象向一端移动,然后清理边界以外的内存。
  • 复制算法:将内存分为两块,每次只使用其中一块,当这一块内存满了,将存活对象复制到另一块,然后清理原来的那一块。

HashMap底层实现:

  • HashMap底层由数组、链表和红黑树组成。当向HashMap中插入元素时,首先根据key的hash值计算出在数组中的位置,如果该位置为空,则直接插入新节点;如果不为空,则会形成链表或红黑树(当链表长度超过一定阈值时会转换为红黑树),新节点插入到链表或红黑树的头部。

HashMap在多线程环境下的问题及解决方法:

  • 问题:在多线程环境下,HashMap可能会出现数据丢失、死循环等问题。例如在扩容时,可能会导致链表形成环形结构,从而在获取元素时出现死循环。
  • 解决方法:使用ConcurrentHashMap。ConcurrentHashMap通过分段锁机制保证线程安全,在进行写操作时,只对需要修改的段加锁,其他段可以继续读操作,大大提高了并发性能。