👋 你好,欢迎来到我的博客!我是【菜鸟不学编程】 我是一个正在奋斗中的职场码农,步入职场多年,正在从“小码农”慢慢成长为有深度、有思考的技术人。在这条不断进阶的路上,我决定记录下自己的学习与成长过程,也希望通过博客结识更多志同道合的朋友。 🛠️ 主要方向包括 Java 基础、Spring 全家桶、数据库优化、项目实战等,也会分享一些踩坑经历与面试复盘,希望能为还在迷茫中的你提供一些参考。 💡 我相信:写作是一种思考的过程,分享是一种进步的方式。 如果你和我一样热爱技术、热爱成长,欢迎关注我,一起交流进步!
全文目录:
-
- ❓前言
- 🧠前置知识你得懂一点,不然真听不懂
- 🚀实战演示:手写一个多线程的Socket服务端
-
- 1️⃣ 服务端代码(支持多客户端并发连接)
- 2️⃣ 客户端代码(多个客户端你自己开多个就行)
- 🧩你看懂了吗?这里才是多线程的灵魂
-
- 🔍几个关键知识点:
- 💡延伸一波,带你入点更深的坑
- ✍️写在最后:代码你可以复制,理解必须原创!
- 📌总结
- 📣你还在用单线程服务?真的不考虑提升一下姿势水平?
- 📝 写在最后
❓前言
唉,说实话,现在做 Java 后端的朋友,如果你还没真正理解多线程服务器的实现机制,我真的是要摇摇头了。你以为 Tomcat 牛,是因为它 logo 好看?还不是背后的线程池机制 + 多路复用模型给力!
今天我不跟你扯那些晦涩难懂的理论,咱们实打实撸个Java 多线程 Socket 服务端实例,从最底层理解多线程服务器的运行机制,看完之后保证你不止知道“怎么用”,更能体会到“为什么这么用”。
🧠前置知识你得懂一点,不然真听不懂
先别急着上代码,我们得先把下面几个概念捋清楚,要不然后面看代码你可能会发出“???”的声音:
- Socket 编程:Java 网络编程最基础的玩意儿,就是一端监听,另一端请求连接,类似打电话。
- 线程/多线程:你主线程一个人在干活,那肯定慢啊,多个线程同时响应多个客户端,这才是正解。
- 阻塞/非阻塞模型:这跟你排队买奶茶一样,阻塞就是“等到买完了才能接下一个”,非阻塞是“多个窗口同时服务”。
- 线程池(ExecutorService):别一个请求就 new 一个线程,GC 都能把你累死。线程池才是正道。
🚀实战演示:手写一个多线程的Socket服务端
来,废话不多说,直接上干货!
1️⃣ 服务端代码(支持多客户端并发连接)
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class MultiThreadedServer {
// 线程池处理客户端连接
private static ExecutorService threadPool = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
System.out.println("😎 服务器启动,端口8888,准备接客…");
while (true) {
// 阻塞等待客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("👉 有客户端连接啦:" + clientSocket.getInetAddress());
// 每个连接交给线程池处理
threadPool.execute(new ClientHandler(clientSocket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 客户端处理类
static class ClientHandler implements Runnable {
private Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
) {
String message;
while ((message = reader.readLine()) != null) {
System.out.println("📨 收到客户端消息:" + message);
writer.write("收到啦,别急!\\n");
writer.flush();
}
} catch (IOException e) {
System.out.println("⚠️ 客户端连接异常:" + e.getMessage());
} finally {
try {
socket.close();
System.out.println("👋 客户端断开连接");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2️⃣ 客户端代码(多个客户端你自己开多个就行)
import java.io.*;
import java.net.*;
public class SimpleClient {
public static void main(String[] args) {
try (
Socket socket = new Socket("127.0.0.1", 8888);
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
) {
String input;
while ((input = console.readLine()) != null) {
writer.write(input + "\\n");
writer.flush();
String response = reader.readLine();
System.out.println("🙋 服务器回复:" + response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
🧩你看懂了吗?这里才是多线程的灵魂
可能你会说,“不就是接个 Socket 然后丢到线程池嘛,这有啥难的?”
这可就是本事啊朋友。真正厉害的服务端不是你能不能“跑起来”,而是你得知道为啥用线程池、怎么防止线程泄露、怎么处理高并发。
🔍几个关键知识点:
为什么用线程池而不是直接 new Thread? 因为频繁创建和销毁线程开销太大,还可能引发OOM(Out of Memory)。线程池能重用线程,而且可以限制最大并发线程数,避免服务器挂掉。
为什么要封装成 ClientHandler? 解耦逻辑,让每个连接单独处理,逻辑清晰又好维护。你直接 inline 写代码以后哭的就是你。
如果客户端断开了怎么办? 那就捕获异常呗,记得关闭 Socket 释放资源。这就是“防御式编程”。
💡延伸一波,带你入点更深的坑
这只是最基础的“阻塞式 BIO 多线程模型”。但在真实生产环境中你会发现:
- 大量并发连接会拖死线程池
- 阻塞 I/O 导致线程等待时间过长
- 可扩展性差
于是就有了:
- NIO(非阻塞 IO):引入 Selector,一个线程可以监听多个通道
- Netty:基于 NIO 封装的异步事件驱动框架,性能炸裂
- Reactor/Proactor 模型:更细粒度的事件驱动方式
你以为这篇文章结束了?不,我这是给你挖坑,下次就把 NIO 和 Netty 拿出来给你好好开堂大课 😎
✍️写在最后:代码你可以复制,理解必须原创!
说真的啊,能坚持读到这里的,基本都是有点“技术洁癖”的人了,我敬你是条好汉。
别小看这几十行代码,背后是线程、IO、网络编程、设计模式等一大串知识点的融合。理解了它,你就不是那种“面试手撕一堆,入职啥都不会”的纸老虎。
📌总结
技术点 | Socket、多线程、线程池 |
实战类型 | 多线程服务端 + 客户端通信 |
编程语言 | Java |
延伸方向 | NIO、Netty、异步模型 |
推荐人群 | Java 初中高级开发者 |
📣你还在用单线程服务?真的不考虑提升一下姿势水平?
如果你看完觉得有帮助,不妨点个赞或者收藏,甚至留言互怼(别客气,我顶得住)。下篇我来手把手写 Netty,让你彻底摆脱“Socket = 土味代码”的误区。
📝 写在最后
如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 👍、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!
我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!
感谢你的阅读,我们下篇文章再见~👋
✍️ 作者:某个被流“治愈”过的 Java 老兵 📅 日期:2025-07-02 🧵 本文原创,转载请注明出处。
评论前必须登录!
注册