2016-05-11 62 views
9

我在Java中有一個多線程回顯服務器的簡單代碼(它將返回的任何內容返回給客戶端)。我正在分析服務器的各種資源,包括線程統計信息。以下是按連接客戶端數量計算的一些統計數據。我的問題是基線(客戶端數量爲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

郵編您接受請 – qwwdfsad

+0

您可以檢查所使用的分析工具線程信息。例如,'jconsole'或'jvisualvm'顯示「線程」選項卡中的所有線程信息。 在這個過程中還會運行一些分析器線程,這將增加計數。 –

+1

我們不知道你的代碼,所以我不知道我們怎麼回答。如果我是你的話,我會在#客戶端爲0時執行線程轉儲,然後當它爲1並比較它們時,你將得到你的答案 –

回答

3

我不知道你用接收那些處理TCP連接無阻塞像Netty使用一個主線程監聽的端口和線程池來處理進來的連接,連接,但通常框架是什麼。這意味着如果線程池被限制爲1個線程,它將至少爲輸入連接打開2個線程。

從netty頁面中看到example,其中2個NioEventLoopGroups在引導服務器時使用。

2個線程是必要的,以不阻止傳入的流量。

+0

我爲服務器添加了一段代碼。 –

+0

您的代碼會阻塞主線程,直到套接字接收到連接。 '''start();'''裏面會發生什麼,因爲這個方法在連接被接受後第一次被調用。 –

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(); 
    } 
} 
+0

我爲服務器添加了一段代碼(如果有幫助的話)。 –

+0

我看到了..你真的需要RMI嗎?你知道有相同的子網限制嗎? –

+0

那麼,客戶端實際上是隻能通過輪詢數據才能工作的狀態機。 RMI是我們能做到的唯一方法。 –