一、线程池
1. 代码示例(企业级最佳实践)
java
运行
import java.util.concurrent.*;
/**
* 线程池企业级使用示例
* 核心:根据业务场景选择合适的线程池参数,避免使用Executors默认创建方式
*/
public class ThreadPoolExample {
// 自定义线程池(核心参数根据CPU核心数和业务特性调整)
private static final ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(
2, // 核心线程数(CPU核心数)
4, // 最大线程数(核心线程数*2)
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(100), // 有界队列(避免内存溢出)
new ThreadFactory() { // 自定义线程工厂(便于排查问题)
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("business-thread-" + (++count));
return thread;
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略(核心线程忙、队列满、最大线程满时,由调用线程执行)
);
public static void main(String[] args) {
try {
// 提交10个任务到线程池
for (int i = 0; i < 10; i++) {
int taskId = i;
THREAD_POOL.submit(() -> {
System.out.println("任务" + taskId + "由线程:" + Thread.currentThread().getName() + "执行");
try {
// 模拟业务处理
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
} finally {
// 优雅关闭线程池(企业级必做)
THREAD_POOL.shutdown();
try {
if (!THREAD_POOL.awaitTermination(1, TimeUnit.MINUTES)) {
THREAD_POOL.shutdownNow();
}
} catch (InterruptedException e) {
THREAD_POOL.shutdownNow();
}
}
}
}
2. 企业面试题
- 基础题:为什么不建议使用 Executors 创建线程池?(答:FixedThreadPool/SingleThreadPool 使用无界队列,可能导致 OOM;CachedThreadPool/ScheduledThreadPool 最大线程数为 Integer.MAX_VALUE,可能创建大量线程导致 OOM)
- 进阶题:线程池的核心参数有哪些?核心线程数、最大线程数、存活时间、队列、线程工厂、拒绝策略
- 实战题:如何优雅关闭线程池?为什么不能直接用 shutdownNow?(答:shutdown () 是平缓关闭,不再接收新任务,等待已提交任务执行完;shutdownNow () 是强制关闭,中断正在执行的任务,返回未执行的任务列表)
- 场景题:如果线程池处理的任务有返回值,应该用 submit 还是 execute?如何获取返回值?(答:用 submit,返回 Future 对象,通过 get () 获取返回值,注意处理 InterruptedException 和 ExecutionException)
3. 企业实际应用
- 接口异步处理:用户请求接口后,核心逻辑同步返回,非核心逻辑(如日志记录、数据统计、消息推送)提交到线程池异步执行,提升接口响应速度。
- 批量任务处理:电商平台订单批量处理、数据导出 / 导入、报表生成等耗时任务,通过线程池并行处理提升效率。
- 中间件底层:Tomcat、Netty 等框架的线程模型核心依赖线程池(如 Tomcat 的 Connector 线程池处理 HTTP 请求)。
二、网络通信(基于 Java Socket)
1. 代码示例(TCP 客户端 - 服务端通信)
服务端(企业级简易版)
java
运行
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) {
// 绑定8888端口
try (ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("服务端启动,监听端口8888...");
// 循环接收客户端连接(实际企业应用会结合线程池处理多客户端)
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("客户端" + clientSocket.getInetAddress() + "连接成功");
// 每个客户端连接分配一个线程处理(实际用线程池)
new Thread(() -> handleClient(clientSocket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 处理客户端请求
private static void handleClient(Socket clientSocket) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
OutputStreamWriter writer = new OutputStreamWriter(clientSocket.getOutputStream())) {
// 读取客户端消息
String msg = reader.readLine();
System.out.println("收到客户端消息:" + msg);
// 响应客户端
writer.write("服务端已收到:" + msg + "\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
java
运行
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) {
// 连接服务端
try (Socket socket = new Socket("localhost", 8888);
OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
// 发送消息给服务端
String msg = "Hello, Server!";
writer.write(msg + "\n");
writer.flush();
// 接收服务端响应
String response = reader.readLine();
System.out.println("服务端响应:" + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 企业面试题
- 基础题:TCP 和 UDP 的区别?(答:TCP 面向连接、可靠、有序、慢;UDP 无连接、不可靠、无序、快)
- 进阶题:Socket 通信中,InputStream 的 read () 方法是阻塞的吗?如何处理非阻塞 IO?(答:默认是阻塞的;NIO 通过 Selector、Channel、Buffer 实现非阻塞 IO)
- 实战题:为什么实际项目中不用原生 Socket 开发网络通信?(答:原生 Socket 需要处理粘包 / 拆包、重连、心跳、序列化等问题,开发成本高,企业一般用 Netty、MINA 等框架)
- 场景题:Netty 的核心组件有哪些?为什么 Netty 比原生 NIO 性能更好?(答:核心组件:Channel、EventLoop、ChannelHandler、Bootstrap;优化点:零拷贝、Reactor 模型、线程模型优化、内存池等)
3. 企业实际应用
- 即时通讯:IM 聊天工具(如企业微信、钉钉)底层基于 TCP/UDP+Netty 实现。
- 微服务通信:Dubbo、gRPC 等 RPC 框架底层基于 Netty 实现跨服务网络通信。
- 中间件交互:Redis、Kafka 等中间件的客户端与服务端通信基于 TCP 协议。
三、反射
1. 代码示例(企业级常用场景)
java
运行
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 反射企业级应用示例:动态调用方法、操作私有属性
* 核心:框架开发(如Spring、MyBatis)的基础
*/
public class ReflectionExample {
// 模拟业务实体类
static class User {
private Long id;
private String name;
public User() {}
public User(Long id, String name) {
this.id = id;
this.name = name;
}
private String getUserName() {
return "用户名:" + this.name;
}
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "'}";
}
}
public static void main(String[] args) throws Exception {
// 1. 获取Class对象(三种方式)
Class<User> userClass = User.class;
// 2. 动态创建对象(无参构造)
User user1 = userClass.getDeclaredConstructor().newInstance();
// 3. 操作私有属性
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true); // 打破封装(访问私有属性必须)
nameField.set(user1, "张三");
Field idField = userClass.getDeclaredField("id");
idField.setAccessible(true);
idField.set(user1, 1L);
System.out.println("动态设置属性后:" + user1);
// 4. 调用私有方法
Method getUserNameMethod = userClass.getDeclaredMethod("getUserName");
getUserNameMethod.setAccessible(true);
String result = (String) getUserNameMethod.invoke(user1);
System.out.println("调用私有方法结果:" + result);
// 5. 通过有参构造创建对象
Constructor<User> constructor = userClass.getDeclaredConstructor(Long.class, String.class);
User user2 = constructor.newInstance(2L, "李四");
System.out.println("有参构造创建对象:" + user2);
}
}
2. 企业面试题
- 基础题:反射的核心作用是什么?获取 Class 对象有哪几种方式?(答:动态获取类信息、调用方法、操作属性,突破封装;方式:类名.class、对象.getClass ()、Class.forName ("全类名"))
- 进阶题:反射为什么可以访问私有属性 / 方法?使用反射时需要注意什么?(答:通过 setAccessible (true) 关闭访问检查;注意:性能损耗、破坏封装性、安全风险)
- 实战题:Spring IoC 容器是如何利用反射创建 Bean 的?(答:扫描指定包下的类,通过 Class.forName 获取 Class 对象,通过反射创建实例,注入属性)
- 场景题:MyBatis 的 Mapper 接口为什么没有实现类却能执行 SQL?(答:MyBatis 通过 JDK 动态代理 + 反射,生成 Mapper 接口的代理类,代理类中通过反射调用对应的 SQL 执行逻辑)
3. 企业实际应用
- 框架核心:Spring IoC/DI、MyBatis、Hibernate 等框架的底层核心依赖反射。
- 动态配置:配置文件(如 XML、YAML)指定类名和方法名,程序启动时通过反射动态加载类、调用方法。
- 注解解析:自定义注解 + 反射实现业务逻辑(如下文注解示例)。
四、注解
1. 代码示例(自定义注解 + 反射解析)
java
运行
import java.lang.annotation.*;
import java.lang.reflect.Method;
/**
* 企业级自定义注解示例:模拟接口权限校验注解
*/
// 1. 定义自定义注解
@Target(ElementType.METHOD) // 注解作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时保留(反射可获取)
@Documented // 生成文档时包含该注解
public @interface PermissionCheck {
// 注解属性(权限编码)
String value() default "";
}
// 2. 使用注解
class UserController {
@PermissionCheck("user:query")
public void queryUser() {
System.out.println("查询用户列表成功");
}
@PermissionCheck("user:delete")
public void deleteUser() {
System.out.println("删除用户成功");
}
public void login() {
System.out.println("登录成功(无需权限校验)");
}
}
// 3. 反射解析注解(模拟权限校验逻辑)
public class AnnotationExample {
public static void main(String[] args) throws Exception {
UserController controller = new UserController();
Class<UserController> clazz = UserController.class;
// 模拟用户拥有的权限
String userPermission = "user:query";
// 获取所有方法,解析注解
for (Method method : clazz.getDeclaredMethods()) {
// 判断方法是否有PermissionCheck注解
if (method.isAnnotationPresent(PermissionCheck.class)) {
PermissionCheck annotation = method.getAnnotation(PermissionCheck.class);
String requiredPermission = annotation.value();
// 权限校验
if (userPermission.equals(requiredPermission)) {
// 有权限,调用方法
method.invoke(controller);
} else {
System.out.println("调用方法" + method.getName() + "失败:无" + requiredPermission + "权限");
}
} else {
// 无注解,直接调用
method.invoke(controller);
}
}
}
}
2. 企业面试题
- 基础题:注解的元注解有哪些?分别起什么作用?(答:@Target:指定注解作用位置;@Retention:指定注解保留阶段;@Documented:生成文档;@Inherited:允许子类继承父类注解)
- 进阶题:注解的 RetentionPolicy 有哪几种?分别适用于什么场景?(答:SOURCE:源码阶段(如 @Override);CLASS:编译阶段(如 Lombok);RUNTIME:运行时(反射解析,如 Spring 注解))
- 实战题:如何自定义一个注解,并通过反射解析它?(答:定义注解→添加元注解→在目标类 / 方法上使用→通过反射获取注解信息并处理)
- 场景题:Spring 中的 @Autowired、@Service、@RequestMapping 注解的实现原理是什么?(答:Spring 启动时扫描注解,通过反射解析注解信息,完成依赖注入、Bean 注册、请求映射等逻辑)
3. 企业实际应用
- 权限控制:如 Spring Security 的 @PreAuthorize、自定义权限注解。
- 接口文档:Swagger 的 @Api、@ApiOperation 注解,自动生成接口文档。
- ORM 映射:JPA 的 @Entity、@Table、@Column 注解,实现实体类与数据库表的映射。
- AOP 切面:Spring 的 @Transactional、@Log 注解,结合 AOP 实现事务管理、日志记录。
总结
- 线程池:核心是合理配置参数 + 优雅关闭,企业中用于异步处理、批量任务,避免 OOM 和线程泄露。
- 网络通信:原生 Socket 仅作基础学习,企业实际用 Netty 等框架解决粘包、性能问题,用于 RPC、IM 等场景。
- 反射:框架开发的核心,可动态操作类 / 方法 / 属性,注意性能和封装性问题。
- 注解:结合反射实现无侵入式扩展,企业中用于权限、配置、文档、AOP 等场景。