2017-02-27 68 views
1

我在Java中遇到了这个问题。 我有一个名为MyServer的服务器类,我想实现一个线程池,每个线程在请求​​发出时运行MyServer的一个方法。我创建了另一个实现了名为MultiThreadedSocketServer的服务器池的类。类是这样的:Java中的线程池中的协调问题

public class MultiThreadedSocketServer { 

public void startServer(MyServer s, int localport, int threadPoolSize) { 
    final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(threadPoolSize); 

    Runnable serverTask = new Runnable() { 
     @Override 
     public void run() { 
      try { 
       ServerSocket serverSocket = new ServerSocket(localport); 
       System.out.println("Waiting for clients to connect..."); 

       while (true) { 
        Socket clientSocket = serverSocket.accept(); 
        clientProcessingPool.submit(new ClientTask(clientSocket, s)); 
       } 
      } catch (IOException e) { 
       System.err.println("Unable to process client request"); 
       e.printStackTrace(); 
      } 
     } 
    }; 
    Thread serverThread = new Thread(serverTask); 
    serverThread.start(); 
} 
} 

名为MultiThreadedSocketServer类具有通过它在一个线程创建客户端Task类参数名为Server秒。客户端的任务类是这样的:

class ClientTask implements Runnable { 
    private final Socket clientSocket; 
    private MyServer s; 

    public ClientTask(Socket clientSocket, MyServer s) { 
     this.s = s; 
     this.clientSocket = clientSocket; 
    } 

    @Override 
    public void run() { 
     System.out.println("Got a client !"); 

     String inputLine = null; 
     try { 

     BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
     // Do whatever required to process the client's request 
     inputLine = in.readLine();   

     if (inputLine.equals("Bye")) { 
      System.out.println("Bye"); 
      System.exit(0); 
     } 

     s.handleRequest(inputLine); 

      clientSocket.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

正如你可以看到,当请求类的MyServer的的handleRequest方法被调用。我想让这个方法运行synchronized,意味着一次只能有一个线程能够运行这个方法。在方法实现之前添加synchronized并没有达到任何效果。

任何人都可以给我正确的方法来做到这一点? 预先感谢您的时间。

PS:我加入了全码

的MyServer类 http://pastebin.com/6i2bn5jj

多线程服务器类 http://pastebin.com/hzfLJbCS

由于这是显而易见的主要创建三个请求用的handleRequest带参数的任务,TASK2和再见。

正确的输出将

Waiting for clients to connect... 
Got a client ! 
This is an input Task 
Request for Task 
Got a client ! 
This is an input task2 
Request for task2 
Got a client ! 
This is an input 
Bye 

而是顺序混合。有时关闭服务器的Bye可以先执行。我想确保订单是主要创建请求的订单。

+0

使MyServer.HandleReq()同步将阻止多个线程在同一个MyServer实例**上同时调用该方法**。你有多少个MyServer实例?附注:请尊重命名约定。 –

+0

只有一个MyServer实例会一直运行。 对不起,我不知道命名约定,如果你想澄清我将编辑我的帖子 –

+1

方法开始一个小写字母。 HandleReq应该是handleReq,或者甚至更好,handleRequest。变量一样。 ThreadPoolSize应该是threadPoolSize。如果您有一个MyServer实例,那么同步该方法即可。你如何测试它没有正确同步? –

回答

2

但相反,订单是混合的。有时关闭服务器的Bye可以先执行。我想确保订单是主要创建请求的订单。

你说你希望服务器按顺序处理请求。这很难确保,因为您打开了3个套接字并将它们写入服务器,但没有等待任何响应。这是依赖于实现的,但我不确定是否有任何保证,当客户端从套接字InputStream写回来时,服务器已收到字节。这意味着从客户端,不能保证IO按您想要的顺序完成。

要查看这是否是问题,我将删除System.exit(0)以查看其他行是否在"Bye"字符串之后创建它。或者你可以在exit(0)之前加上Thread.sleep(5000);

一种简单的修复方法是确保您的PrintStream已启用自动刷新功能。至少会在套接字上调用flush,但即使如此,客户端和服务器之间也存在竞争状态。如果自动刷新不起作用,那么我会让你的客户端等待来自服务器的响应。那么第一个客户端会在写入第一个命令并等待确认之后再进入第二个命令。

就原来的问题而言,由于竞争条件的原因,锁定服务器将无济于事。 "Bye"可能会首先将服务器锁定并将其锁定。

这些围绕如何在多线程程序中同步线程的问题对我来说确实没有意义。线程的整个是它们并行运行并且不必按任何特定顺序运行。您越强迫程序以特定顺序吐出输出内容,您越是争论没有任何线程的写作。

希望这会有所帮助。

0

如果问题是bye消息在可以处理其他请求之前杀死服务器,则一种解决方案可能不会在bye上调用System.exit(0);

bye消息可能会设置一个标志块来处理进一步的请求,并且还会通知某些其他机制在线程池处于空闲状态并且没有任何请求需要处理时调用System.exit(0);