马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
弁言
在Java网络编程的世界中,理解不同的I/O模子对于构建高效的网络应用至关重要。本文将带您从最基础的阻塞式I/O模子出发,渐渐过渡到更高效的线程池模子,资助您建立对Java网络编程的根本认识。
阻塞式I/O模子:连续接一线程
阻塞式I/O是Java网络编程中最简单直观的模子。在这种模子中,服务器为每个客户端连接创建一个专用线程。
SimpleServer实现
- public class SimpleServer {
- public static void main(String[] args) throws IOException {
- ServerSocket serverSocket = new ServerSocket(8080);
- System.out.println("服务器启动,监听端口:8080...");
-
- while (true) {
- // 接受客户端连接,这是一个阻塞调用
- Socket clientSocket = serverSocket.accept();
- System.out.println("客户端已连接:" + clientSocket.getInetAddress());
-
- // 为每个客户端创建一个新线程
- new Thread(() -> handleClient(clientSocket)).start();
- }
- }
-
- private static void handleClient(Socket clientSocket) {
- try (
- BufferedReader in = new BufferedReader(
- new InputStreamReader(clientSocket.getInputStream()));
- PrintWriter out = new PrintWriter(
- clientSocket.getOutputStream(), true)
- ) {
- String inputLine;
- while ((inputLine = in.readLine()) != null) {
- System.out.println("收到消息:" + inputLine);
- out.println("服务器回复:" + inputLine);
- }
- } catch (IOException e) {
- System.out.println("处理客户端连接异常:" + e.getMessage());
- } finally {
- try {
- clientSocket.close();
- } catch (IOException e) {
- System.out.println("关闭客户端连接异常:" + e.getMessage());
- }
- }
- }
- }
复制代码 阻塞式I/O的优缺点
优点:
- 实现简单直观
- 客户端处置处罚逻辑相互独立
- 得当连接数较少的场景
缺点:
- 每个连接占用一个线程,资源消耗大
- 连接数增加时,线程数爆炸
- 线程上下文切换开销大
- 不得当高并发场景
线程池模子:资源复用的第一步
为了办理连续接一线程模子的资源浪费问题,线程池模子应运而生。它通过复用有限数量的线程来处置处罚大量连接。
ThreadPoolServer实现
- public class ThreadPoolServer {
- public static void main(String[] args) throws IOException {
- // 创建固定大小的线程池
- ExecutorService executor = Executors.newFixedThreadPool(10);
- ServerSocket serverSocket = new ServerSocket(8080);
- System.out.println("线程池服务器启动,监听端口:8080...");
-
- try {
- while (true) {
- // 接受客户端连接,这仍然是一个阻塞调用
- Socket clientSocket = serverSocket.accept();
- System.out.println("客户端已连接:" + clientSocket.getInetAddress());
-
- // 将客户端处理任务提交到线程池
- executor.submit(() -> handleClient(clientSocket));
- }
- } finally {
- serverSocket.close();
- executor.shutdown();
- }
- }
-
- private static void handleClient(Socket clientSocket) {
- // 客户端处理逻辑与SimpleServer相同
- try (
- BufferedReader in = new BufferedReader(
- new InputStreamReader(clientSocket.getInputStream()));
- PrintWriter out = new PrintWriter(
- clientSocket.getOutputStream(), true)
- ) {
- String inputLine;
- while ((inputLine = in.readLine()) != null) {
- System.out.println("线程 " + Thread.currentThread().getName()
- + " 收到消息:" + inputLine);
- out.println("服务器回复:" + inputLine);
- }
- } catch (IOException e) {
- System.out.println("处理客户端连接异常:" + e.getMessage());
- } finally {
- try {
- clientSocket.close();
- } catch (IOException e) {
- System.out.println("关闭客户端连接异常:" + e.getMessage());
- }
- }
- }
- }
复制代码 线程池模子的优缺点
优点:
- 控制并发线程数量,避免线程爆炸
- 线程复用,淘汰创建和销毁线程的开销
- 可以根据体系负载调整线程池巨细
- 得当中等并发场景
缺点:
- 每个连接的I/O操纵仍然是阻塞的
- 线程数量仍然与并发连接数相关
- 高并发场景下仍有性能瓶颈
总结
从阻塞式I/O到线程池模子,我们迈出了Java网络编程优化的第一步。线程池模子通过复用线程资源,在一定水平上提高了服务器的并发处置处罚本领。然而,在面对更高并发的场景时,我们必要探索更先辈的模子,如NIO和Reactor模式,这将在后续文章中详细先容。
|