我在Java中有一个简单的多线程echo服务器代码(它将返回给客户端返回的内容返回)。我分析了服务器的各种资源,包括线程统计信息。以下是根据已连接客户端数量的一些统计信息。我的问题是基线(客户0的数量)与非基线的比较!
1)为什么当单个客户端连接时,总线程数增加2? (对于其余的,增加1是有意义的)
2)两个非守护程序线程是什么?!为什么守护进程最初增加1然后固定?
它们是随机的吗?!
# clients 0 1 2 3 4 5 6 7 8 9 10
Total Started Thread Count 15 18 19 20 21 22 23 24 25 26 27
Thread count 14 16 17 18 19 20 21 22 23 24 25
Peak thread count 14 16 17 18 19 20 21 22 23 24 25
Daemon thread count 12 13 13 13 13 13 13 13 13 13 13
这是服务器的代码段。我同时使用RMI(用于客户端轮询消息)和服务器套接字(用于客户端发送消息)。如果需要其他课程,请告诉我。
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Vector;
public class ServerRMI extends Thread implements Hello {
//centralized token manager runs polling server and socket server to receive updated tokens
static Vector<String> tokenList= new Vector<String>();
protected Socket clientSocket;
static int RMIRegistryPort=9001;
static int SocketServerPort=9010;
public static void main(String[] args) throws IOException {
try {
ServerRMI obj = new ServerRMI();
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(RMIRegistryPort);
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
ServerSocket serverSocket = null;
//initialize token list
//A needs to execute first
tokenList.add(0,"0");
try {
serverSocket = new ServerSocket(SocketServerPort);
System.out.println("Connection Socket Created");
try {
while (true) {
System.out.println("Waiting for Connection");
new ServerRMI(serverSocket.accept());
}
} catch (IOException e) {
System.err.println("Accept failed.");
}
} catch (IOException e) {
System.err.println("Could not listen on port: "+SocketServerPort);
} finally {
try {
serverSocket.close();
} catch (IOException e) {
System.err.println("Could not close port: "+SocketServerPort);
}
}
}
private ServerRMI(Socket clientSoc) {
clientSocket = clientSoc;
start();
}
public ServerRMI() {}{
// TODO Auto-generated constructor stub
}
public void run() {
System.out.println("New Communication Thread Started");
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
tokenList.add(0,inputLine);
System.out.println("Server received: " + inputLine);
// System.out.println(" ququ size: "+queue.size());
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
} catch (IOException e) {
System.err.println("Problem with Communication Server");
}
}
public String pollServer() {
if(!tokenList.isEmpty()){
String data = tokenList.get(0);
System.out.println("Poll data: "+data);
return data;
} else{
return tokenList.size()+"";
}
}
}
答案 0 :(得分:3)
我不确定你使用什么来接收这些连接,但通常处理非阻塞的TCP连接的框架如Netty使用主线程来监听端口和线程池来处理连接。这意味着如果线程池限制为1个线程,它将至少为incomming连接打开2个线程。
在netty页面中查看此example,其中在引导服务器时使用了2个NioEventLoopGroup。
这两个线程是不必阻止传入流量的必要条件。
答案 1 :(得分:3)
我希望您查看了VisualVM Profiler中的线程名称。通常,线程名称可以让您了解启动的内容。
ad 1)这很可能是一些TCP / IP后台(清理,轮询)线程,一旦你从外面有一些TCP / IP连接就会产生。
当客户回到0时会发生什么。额外的线程会消失吗?
根据JVM供应商和版本,答案可能会有很大不同。所以我认为你需要查看JVM内部有关套接字和线程的信息。
下面的示例更直接(没有RMI)
import java.net.*; // for Socket, ServerSocket, and InetAddress
import java.io.*; // for IOException and Input/0utputStream
public class TCPEchoServer {
private static final int BUFSIZE = 32; // Size of receive buffer
public static void main(String[] args) throws lOException {
if (args.length != i) // Test for correct # of args
throw new lllegalArgumentException("Parameter(s): <Port>");
int servPort = Integer.parselnt(args[0]);
// Create a server socket to accept client connection requests
ServerSocket servSock = new ServerSocket(servPort);
int recvMsgSize; // Size of received message
byte[] byteBuffer = new byte[BUFSlZE]; // Receive buffer
}
for (;;) { // Run forever, accepting and servicing connections
Socket clntSock = servSock.accept(); // Get client connection
System.out.println("Handling client at " +
clntSock.getInetAddress().getHostAddress() + " on port " +
clntSock, getPort());
InputStream in = clntSock, getlnputStream();
OutputStream out = clntSock.getOutputStream();
// Receive until client closes connection, indicated by-i return
while ((recvMsgSize = in .read(byteBuffer)) != -I)
out.write(byteBuffer, O, recvMsgSize);
clntSock, close();
}
}