面试题答案
一键面试实现思路
- 设置合理的拒绝策略:当线程池已满,无法处理新的任务时,需要选择合适的拒绝策略来处理这些任务,而不是直接丢弃。
- 排队等待:可以使用一个额外的队列,如
BlockingQueue
,将无法立即处理的客户端连接请求暂存起来,待线程池有空闲线程时再处理。 - 动态调整线程池大小:根据系统的负载情况,动态调整线程池的大小,以适应不断变化的请求数量。
关键代码片段
- 创建线程池并设置拒绝策略:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
// 创建一个有界队列
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(100);
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, // 核心线程数
50, // 最大线程数
10, // 线程存活时间
TimeUnit.SECONDS,
queue,
new ThreadPoolExecutor.CallerRunsPolicy()); // 使用CallerRunsPolicy拒绝策略
在上述代码中,CallerRunsPolicy
拒绝策略会让提交任务的线程(通常是主线程)来执行任务,这样可以保证任务不会被丢弃,同时也能起到一定的限流作用。
- 处理客户端连接请求:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
private static final int PORT = 8080;
private final ThreadPoolExecutor executor;
public Server(ThreadPoolExecutor executor) {
this.executor = executor;
}
public void start() {
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server started on port " + PORT);
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected: " + clientSocket);
// 将客户端连接处理任务提交到线程池
executor.submit(() -> {
try {
// 处理客户端连接的具体逻辑
handleClient(clientSocket);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void handleClient(Socket clientSocket) throws IOException {
// 具体的客户端处理逻辑,例如读取和写入数据
}
}
在start
方法中,通过ServerSocket
监听客户端连接,一旦有新连接,就将处理任务提交到线程池。如果线程池已满,根据设置的拒绝策略处理任务。
- 动态调整线程池大小:
// 根据系统负载动态调整线程池大小
public void adjustThreadPoolSize(int newCorePoolSize, int newMaximumPoolSize) {
executor.setCorePoolSize(newCorePoolSize);
executor.setMaximumPoolSize(newMaximumPoolSize);
}
可以根据系统的负载情况(如CPU使用率、任务队列长度等)调用adjustThreadPoolSize
方法动态调整线程池的核心线程数和最大线程数。