我在Java中遇到这个问题。 我有一个名为MyServer的服务器类,我想实现一个线程池,其中每个线程在请求到来时运行MyServer的方法。我创建了另一个实现名为MultiThreadedSocketServer的服务器池的类。课程是这样的:
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的类有一个名为Server s的参数,它在客户端Task类中传递它,并创建一个线程。客户端任务类是这样的:
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 Class http://pastebin.com/6i2bn5jj
多线程服务器类 http://pastebin.com/hzfLJbCS
正如在main中显而易见的,我使用带有参数Task,task2和Bye的handleRequest创建了三个请求。
正确的输出是
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 :(得分:2)
但相反,订单是混合的。有时可以先执行关闭服务器的Bye。我想确保订单是在主要订单中创建请求的订单。
您说您希望服务器按顺序处理请求。这很难确保,因为您打开3个套接字并将它们写入服务器但不等待任何响应。这是依赖于实现的,但我不确定当客户端从执行套接字InputStream
返回时,确保服务器已收到字节。这意味着从客户端,无法保证IO按您想要的顺序完成。
要查看这是否是问题,我会删除System.exit(0)
以查看其他行是否成功,就在"Bye"
字符串之后。或者您可以在Thread.sleep(5000);
之前添加exit(0)
。
一种简单的修复方法是确保您的PrintStream
已启用自动刷新功能。至少会在套接字上调用flush,但即使这样,客户端和服务器之间也存在竞争条件。如果自动刷新不起作用,那么我让你的客户端等待来自服务器的响应。那么第一个客户端将编写第一个命令并等待确认,然后再转到第二个命令。
就原始问题而言,由于竞争条件,锁定服务器无济于事。 "Bye"
可能会使它成为第一个并锁定服务器。
关于如何在多线程程序中同步线程的这些问题对我来说真的没有意义。线程的整个 point 是它们并行异步运行而不必以任何特定顺序运行。你强迫你的程序以特定的顺序吐出输出的次数越多,你就越多地争论没有任何线程来写这个。
希望这有帮助。
答案 1 :(得分:0)
如果问题是bye
消息在处理其他请求之前杀死了服务器,则一种解决方案可能是不在System.exit(0);
上调用bye
。
bye
消息可以设置一个标志块来处理进一步的请求,并且当线程池空闲且没有剩余请求处理时,还通知其他一些机制调用System.exit(0);
。