所以我有这个小代码:
public class MyCounterClass {
private static int counter = 0;
synchronized public static int getCounter(){
return counter++;
}
}
这是服务器:
public class MyServer implements Runnable{
public static void go() throws IOException {
System.out.println("MyServer: Go called...");
ServerSocket serverSocket = new ServerSocket(5000);
while(true){
Socket socket = serverSocket.accept();
System.out.println(time() + "MyServer: Connection accepted!");
OutputStream outputStream = socket.getOutputStream();
System.out.println(time() + "MyServer: socket.getOutputStream");
PrintWriter printWriter = new PrintWriter(outputStream);
System.out.println(time() + "MyServer: New PrintWriter object created!");
printWriter.write(time() + "Hello from my socket!");
System.out.println(time() + "MyServer: printwriter.write method called..");
printWriter.flush();
System.out.println(time() + "MyServer: Flushed!");
printWriter.close();
System.out.println(time() + "MyServer: printWriter closed...");
}
}
public static String time(){
return String.valueOf(MyCounterClass.getCounter()) + " ";
}
@Override
public void run() {
try {
go();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这是客户:
public class MyClient implements Runnable {
public static void go() throws IOException {
Socket socket = new Socket("localhost",5000);
System.out.println(time() + "My Client: Connection established...");
InputStream inputStream = socket.getInputStream();
System.out.println(time() + "MyClient: socket.getInputStream...");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(time() + "MyClient: BufferedReader object created...");
System.out.println(time() + bufferedReader.readLine());
}
public static String time(){
return String.valueOf(MyCounterClass.getCounter()) + " ";
}
@Override
public void run() {
try {
go();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我如何运行程序:
public class TestClass {
public static void main(String[] args) throws IOException, InterruptedException {
Thread server = new Thread(new MyServer());
server.start();
Thread.sleep(750);
Thread client = new Thread(new MyClient());
client.start();
}
}
输出:
MyServer: Go called...
0 My Client: Connection established...
1 MyServer: Connection accepted!
2 MyClient: socket.getInputStream...
3 MyServer: socket.getOutputStream
4 MyClient: BufferedReader object created...
6 MyServer: New PrintWriter object created!
8 MyServer: printwriter.write method called..
9 MyServer: Flushed!
10 MyServer: printWriter closed...
5 7 Hello from my socket!
我的问题是,最后一行怎么能得到" 5和7"?
答案 0 :(得分:4)
由于客户端和服务器是独立的线程,因此它们不会按顺序输出时间。
主要的混乱是因为这一行:
System.out.println(time() + bufferedReader.readLine());
似乎println正在及时回归"。然而,正在发生的事情是,time()方法被称为回溯时间" 5"。但是,由于普通的Java套接字是阻塞的,所以bufferedReader.readLine()调用会挂起,直到服务器实际可以获得数据,直到服务器发送数据之后才会发生这种情况(当然)。然后,一旦readLine方法返回,println调用实际上就完成了。
如果你想看到更多"逻辑"进度,将最后一个客户行更改为:
String result = bufferedReader.readLine();
System.out.println(time() + result);
这会延迟客户的上一次()电话,直到在实际收到回复之后。
答案 1 :(得分:2)
因为您在服务器和客户端的服务器上添加(prepend = oposite of append)时间 ,所以
printWriter.write(time() + "Hello from my socket!");
'7'会被添加到您的消息中,然后'7 Hello from my socket!'已发送,然后5
被添加到您的客户端:
System.out.println(time() + bufferedReader.readLine());
导致5 7 Hello from my socket!
。
那么time()
如何先返回7然后再返回5?
好吧,不因为counter
不是volatile
,请查看原因here。
现在考虑以下场景:在您的客户端,调用time()
并存储结果,然后线程等待它接收数据,然后服务器创建数据并发送它们。它将解释为什么客户端在发送的消息上打印较低的值然后服务器。
您也可以尝试写:
System.out.println(time() + bufferedReader.readLine() + time());
要查看time
的第二次调用是否会提供更大的值,即第一次调用+ 1,因为readLine()
冻结当前线程直到某些要读取的数据可用。