Thread-Per-Message设计模式
每一个业务请求都开辟一个线程去执行,来保证高效。
聊天室实例 服务端
public class ChatServer {
// 服务端口
private final int port;
// 线程池 这里用了自定义的线程池
private ThreadPool threadPool;
// 服务端 Socket
private ServerSocket serverSocket;
public ChatServer(int port) {
this.port = port;
}
public ChatServer(){
this(13313);
}
// 开启服务端
public void startServer() throws IOException{
// 初始化线程池 socket等信息
this.threadPool = new BasicThreadPool(1,4,2,1000);
this.serverSocket = new ServerSocket(port);
this.serverSocket.setReuseAddress(true);
System.out.println("网络聊天服务端开启 端口号为"+port);
this.listen();
}
private void listen() throws IOException {
while (true){
// accept方法是阻塞方法 当有新链接进入时才会有返回值 返回值是客户端的链接
Socket client = serverSocket.accept();
// 将客户端作为一个请求request开辟一个新线程执行对应任务
this.threadPool.execute(new ClientHandler(client));
}
}
public static void main(String[] args) throws IOException {
new ChatServer().startServer();
}
}
客户端
public class ClientHandler implements Runnable {
// 客户端的socket
private final Socket socket;
// 客户的id信息
private final String clientId;
public ClientHandler(final Socket client) {
this.socket = client;
this.clientId = client.getInetAddress().getHostAddress()+":"+client.getPort();
}
@Override
public void run() {
try{
this.chat();
}catch (IOException e){
e.printStackTrace();
}
}
private void chat() throws IOException {
BufferedReader reader = wrap2Reader(this.socket.getInputStream());
PrintStream print = wrap2Print(this.socket.getOutputStream());
String received;
while ((received = reader.readLine()) != null){
System.out.println("client: "+clientId+" MSG:"+received);
// 退出程序
if (("quit").equals(received)){
write2Client(print,"client close");
socket.close();
break;
}
// 发送消息给客户端
write2Client(print,"Server MSG:"+received);
}
}
// 将输入字节流封装成BufferedReader 缓冲字符流
private BufferedReader wrap2Reader(InputStream inputStream){
return new BufferedReader(new InputStreamReader(inputStream));
}
// 将输出字节流封装成PrintStream
private PrintStream wrap2Print(OutputStream outputStream){
return new PrintStream(outputStream);
}
// 向客户端发送消息
private void write2Client(PrintStream print,String message){
print.println(message);
print.flush();
}
}
测试画面
客户端用 telnet 127.0.0.1 13313 的命令行方式启动

总结
因为是一个业务开辟一个线程执行任务 而内存中的线程数是有限的所以要使用线程池的思想来管理执行开辟出来的线程。

被折叠的 条评论
为什么被折叠?



