阻塞模型的问题关键**不在于是否使用多线程(包括线程池)处理并发请求,而在于accept(),read()的操作点都被阻塞了。**下面近似模拟这个问题,模拟了20个客户端(用20个线程模拟),利用Java的同步计数器CountDownLatch保证这20个线程都初始化完成后再同时向服务器发送请求。
- 客户端代码
package testBSocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;
public class SocketClientDaemon {
public static void main(String[] args) {
int clientNumber = 20;
CountDownLatch countDownLatch = new CountDownLatch(clientNumber);
for (int i = 0; i < clientNumber ; i++, countDownLatch.countDown()) {
SocketClientRequestThread client = new SocketClientRequestThread(i,
countDownLatch);
new Thread(client).start();
}
// TODO
synchronized (SocketClientDaemon.class) {
try {
SocketClientDaemon.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SocketClientRequestThread implements Runnable {
private int clientNum;
private CountDownLatch countDownLatch;
public SocketClientRequestThread(int clientNum, CountDownLatch countDownLatch) {
this.clientNum = clientNum;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
Socket socket = null;
InputStream clientResponse = null;
OutputStream clientRequest = null;
try {
socket = new Socket("localhost", 12212);
// TODO 输入输出流是针对内存来说的
clientResponse = socket.getInputStream();
clientRequest = socket.getOutputStream();
this.countDownLatch.await();
clientRequest.write(("这是第" + this.clientNum + "个客户端的请求").getBytes());
clientRequest.flush();
System.out.println("第" + this.clientNum + "个客户端发送完成,等待回复消息");
int maxLen = 1024;
byte[] contextBytes = new byte[maxLen];
int readLen;
String message = "";
while ((readLen = clientResponse.read(contextBytes, 0, maxLen)) != -1) {
message += new String(contextBytes, 0, readLen);
}
System.out.println("第" + this.clientNum + "个客户端收到服务器的信息:" + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
if (clientRequest != null) {
clientRequest.close();
}
if (clientResponse != null) {
clientResponse.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- 服务端代码
package testBSocket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer2 {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(12212);
try {
while (true) {
Socket socket = serverSocket.accept();
SocketServerThread socketServerThread = new SocketServerThread(socket);
new Thread(socketServerThread).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class SocketServerThread implements Runnable {
private Socket socket;
public SocketServerThread (Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream is = null;
OutputStream os = null;
try {
is = socket.getInputStream();
os = socket.getOutputStream();
Integer sourcePort = socket.getPort();
int maxLen = 1024;
byte[] contextBytes = new byte[maxLen];
String message = "";
// //不能这样写,不然会阻塞在这里
// while ((readLen = is.read(contextBytes, 0, maxLen)) != -1) {
// message += new String(contextBytes, 0, readLen);
// }
int readLen = is.read(contextBytes, 0, maxLen);
message = new String(contextBytes, 0, readLen);
System.out.println("服务器收到端口" + sourcePort + "的信息" + message);
os.write("服务器回复消息".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}