Java 基础面试题速记通关版 | 面试刷题 mianshiya.comPDF下载

Java 基础面试题速记通关版 | 面试刷题 mianshiya.com

by 面试鸭 下载量 1157
Java 作为广泛应用的编程语言,基础扎实是后端开发的关键。Java 基础面试的重点知识点包括数据类型与运算符、字符串操作、异常处理、面向对象设计、类与接口的实现、集合框架的使用、多线程编程、JVM 运行原理以及 Java 8 的新特性。

你使用过哪些 JDK 提供的工具?

JDK 自带的工具其实是日常排查问题的利器,很多场景下压根不需要额外依赖第三方工具。

jps 相当于 Java 版的 ps,能快速列出当前机器上所有正在运行的 Java 进程 PID。排查多实例部署时特别有用,几秒钟就能定位到目标进程。

jstat 是看 JVM 运行状态最轻量的方式,尤其是监控 GC 频率和堆内存变化。比如想确认是不是频繁 Full GC,用 jstat -gcutil <pid> 1000 每秒打一次数据,趋势一目了然。

jstack 对应线程分析,定位死锁或高 CPU 很直接。拿到进程 PID 后执行 jstack <pid>,输出的线程栈里如果看到 WAITING 状态集中在某个锁对象,基本就能锁定问题点。线上服务响应卡顿,第一反应就是抓 thread dump 看有没有线程堆积。

jmap 可以导出堆内存快照,配合 jhat 或 MAT 分析内存泄漏。不过要注意的是,jmap -dump 在堆大的时候会触发长时间 STW,生产环境得谨慎操作。

其实从 JDK 8 开始,Arthas 虽然是阿里开源的,但已经成了事实标准。它把上面这些命令都整合了,还能动态 trace 方法调用、watch 参数返回值,排查线上问题效率提升非常明显。

什么是 Selector?

Selector 是 Java NIO 里用来做事件监听的核心组件,一个线程通过它就能同时监控多个通道的 I/O 状态,比如有没有数据可读、能不能写入。

你想想,传统 IO 一个连接就得占一个线程,1000 个连接就得分 1000 个线程去处理,系统压根扛不住。而用了 Selector,一个线程轮询多个 Channel 的就绪事件,资源利用率直接拉满,这就是为什么 Netty、Dubbo 这些高性能中间件底层都靠它撑着。

每个 Channel 注册到 Selector 上时得绑定一个 SelectionKey,表示“我对哪些事件感兴趣”,比如 OP_READ、OP_WRITE。调用 select() 方法后,线程会阻塞直到有至少一个通道就绪,然后返回就绪的 key 集合,挨个处理就行。

代码上大概是这样:

java
复制代码
Selector selector = Selector.open(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); while (true) { int readyChannels = selector.select(); // 阻塞等待就绪事件 if (readyChannels == 0) continue; Set<SelectionKey> keys = selector.selectedKeys(); for (SelectionKey key : keys) { if (key.isReadable()) { /* 处理读 */ } keys.remove(key); } }

注意非阻塞模式是前提,阻塞 IO 调了 select() 也没意义。另外 select() 返回的是就绪的通道数,不是所有注册的。

整个模型叫多路复用,Linux 上实际是 epoll 在背后干活。

什么是 Channel?

Channel 是 Java NIO 的核心组件,可以看作是数据传输的通道,负责从缓冲区读写数据。它和传统的 IO 流不同,Channel 是双向的,既能读也能写,而流一般是单向的。

1)常见的 Channel 实现有 FileChannel、SocketChannel、ServerSocketChannel 和 DatagramChannel。比如 Netty 就基于 NioSocketChannel 做网络通信,用统一的抽象屏蔽底层差异。

2)Channel 本身不直接操作数据,数据总是流向 Buffer。读数据时,数据从 Channel 进入 Buffer;写数据时,数据从 Buffer 写入 Channel。这种设计让数据处理更灵活,也便于零拷贝技术的应用。

3)在高并发场景下,Channel 配合 Selector 实现多路复用。一个线程就能监控多个 Channel 的事件,比如连接就绪、读就绪,避免为每个连接开线程,扛住几万并发连接很常见。

使用时要注意,Channel 必须配置为非阻塞模式才能注册到 Selector,否则会抛异常。另外,关闭 Channel 会释放对应的文件描述符,这个资源很宝贵,Linux 下一般默认最多 1024 个,用完就得调优。

如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?

调用 start() 方法的本质是让 JVM 将线程加入调度队列,真正触发 run() 的执行。线程的状态机决定了它只能从 NEW 状态被启动一次。

1)第一次调用 start(),线程状态从 NEW 变为 RUNNABLE,等待 CPU 调度执行 run() 方法。

2)第二次再调用 start(),JVM 会检查线程当前状态,发现已经不是 NEW,直接抛出 IllegalThreadStateException

这个异常是运行时异常,不强制捕获,但一旦发生程序就会中断。常见于误把线程对象当工具复用,比如在循环里反复启动同一个线程。

java
复制代码
Thr
下载 APP