面试题答案
一键面试策略一:线程池优化
- 原理说明:原系统使用多线程处理客户端连接,在高并发时频繁创建和销毁线程会带来较大开销。使用线程池可以复用线程,减少线程创建和销毁的开销,提高系统性能。线程池维护一定数量的线程,当有任务到达时,从线程池中获取线程执行任务,任务完成后线程返回线程池等待下一个任务。
- 代码实现方式:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
executorService.submit(() -> {
// 处理客户端连接的业务逻辑
System.out.println(Thread.currentThread().getName() + " 正在处理任务");
});
}
executorService.shutdown();
}
}
在实际应用中,将处理客户端连接的代码放在submit
的Runnable
中。
策略二:NIO(New I/O)替换BIO
- 原理说明:BIO是阻塞式I/O,每个客户端连接都需要一个独立的线程来处理,在高并发时线程数量剧增,消耗大量系统资源。NIO是非阻塞式I/O,它基于通道(Channel)和缓冲区(Buffer)进行操作,通过Selector实现多路复用,可以用一个线程管理多个通道,大大减少线程数量,提高系统的并发处理能力。
- 代码实现方式:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class NIOExample {
private static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(PORT));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
if (bytesRead > 0) {
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
System.out.println("收到数据: " + new String(data));
}
}
iterator.remove();
}
}
}
}
此代码展示了基本的NIO服务器端接收客户端连接和读取数据的过程。
策略三:优化缓冲区
- 原理说明:在BIO处理客户端连接时,合理设置缓冲区大小可以减少I/O操作次数。过小的缓冲区会导致频繁的I/O读写,增加系统开销;过大的缓冲区可能会浪费内存。合适大小的缓冲区可以提高数据传输效率,从而提升系统性能。
- 代码实现方式:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class BufferOptimizationExample {
private static final int PORT = 8080;
private static final int BUFFER_SIZE = 8192;
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
while (true) {
try (Socket clientSocket = serverSocket.accept();
InputStream inputStream = new BufferedInputStream(clientSocket.getInputStream(), BUFFER_SIZE);
OutputStream outputStream = new BufferedOutputStream(clientSocket.getOutputStream(), BUFFER_SIZE)) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述代码中,通过BufferedInputStream
和BufferedOutputStream
设置了缓冲区大小为BUFFER_SIZE
,优化了数据的读写操作。