【问题标题】:Why does multithreading my single-threaded simple echo server cause it to stop working?为什么多线程我的单线程简单回显服务器会导致它停止工作?
【发布时间】:2014-07-15 22:15:23
【问题描述】:

这个单线程回显服务器工作正常。

public class Server {
    public static void main(String[] args) throws IOException {
        try (ServerSocket sc = new ServerSocket(1111)) {
            while (true) {
                try (Socket dataSocket = sc.accept();
                        BufferedReader is = new BufferedReader(
                                new InputStreamReader(
                                        dataSocket.getInputStream()));
                        PrintWriter out = new PrintWriter(
                                dataSocket.getOutputStream());) {
                    String line;
                    while ((line = is.readLine()) != null) {
                        System.out.println(line);
                        out.println(line);
                        out.flush();
                        if (line.equals("Bye."))
                            break;
                    }
                }
            }
        }
    }
}

但是为什么这个多线程版本不起作用呢?它只是传递输入和输出流来构造一个 TestServer1 线程并启动它。没什么特别的。但是不知何故,当客户端连接到该服务器时,run() 中会抛出一个"Stream close" 异常,并打印"error in run"

public class TestServer1 extends Thread{
    BufferedReader in;
    PrintWriter out;
    public TestServer1(BufferedReader in, PrintWriter out){
        this.in=in;
        this.out=out;       
    }
    @Override
    public void run(){
        String line;
        try{
        while ((line = in.readLine()) != null) {
            System.out.println(line);
            out.println(line);
            out.flush();
            if (line.equals("Bye."))
                break;
        }
        } catch (IOException e){
            System.out.println("error in run");
            e.printStackTrace();
        }       
    }
    public static void main(String[] args) throws IOException {
        try (ServerSocket sc = new ServerSocket(1111)) {
            while (true) {
                try (Socket dataSocket = sc.accept();
                        BufferedReader in = new BufferedReader(
                                new InputStreamReader(
                                        dataSocket.getInputStream()));
                        PrintWriter out = new PrintWriter(
                                dataSocket.getOutputStream());) {
                    TestServer1 ts1=new TestServer1(in, out);
                    ts1.start();        
                }
            }
        }
    }
}

这是堆栈跟踪

error in run
java.io.IOException: Stream closed
    at java.io.BufferedReader.ensureOpen(BufferedReader.java:115)
    at java.io.BufferedReader.readLine(BufferedReader.java:310)
    at java.io.BufferedReader.readLine(BufferedReader.java:382)
    at server.TestServer1.run(TestServer1.java:22)

【问题讨论】:

  • 请在问题中添加完整的堆栈跟踪。
  • 我认为发生的事情是,在您在 run 方法中完成写入之前,您正在使用“Try With Resources”隐式关闭输出流
  • @Amir 谢谢,你是对的。主线程退出 try 块后,流被关闭。而且你的版本很有效。

标签: java multithreading


【解决方案1】:

Java 7:尝试资源

使用 Java 7,您可以在 try 中创建一个或多个“资源” 陈述。 “资源”是实现 java.lang.AutoCloseable 接口。该资源将是 自动关闭并结束try块。

来自 javadocs:

static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
               new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

}

在本例中,try-with-resources 语句中声明的资源是 BufferedReader。声明语句紧跟在 try 关键字之后的括号内。 Java SE 7 及更高版本中的 BufferedReader 类实现了接口 java.lang.AutoCloseable。因为 BufferedReader 实例是在 try-with-resource 语句中声明的,所以无论 try 语句是正常完成还是突然完成(作为 BufferedReader 方法的结果),它都会被关闭。

链接:http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

所以这可能是原因,当您的流超出范围时会自动关闭。

【讨论】:

  • 感谢您的链接。是的,封闭的溪流是问题的根源。
【解决方案2】:

try() 就是原因。流将在 try (.....) 块后关闭。 请测试此代码:

 while (true) {
    try { 
        Socket dataSocket = sc.accept();
        BufferedReader in = new BufferedReader(
            new InputStreamReader(
            dataSocket.getInputStream()));
        PrintWriter out = new PrintWriter(
            dataSocket.getOutputStream());
        TestServer1 ts1 = new TestServer1 (in, out);
        ts1.start();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

P.S:你需要在线程run()方法中关闭流。

【讨论】:

  • 你是对的。 try-block 关闭了流。您的版本应该可以工作。
【解决方案3】:

在下面试试这个版本 - 它未经测试。但正如我在评论中所说,我相信您在 TryWithResources 中过早地关闭了输出流

public class TestServer1 extends Thread{
    Socket connection;

    public TestServer1(Socket connection){
        this.connection = connection;       
    }

    @Override
    public void run(){

        try (BufferedReader in = new BufferedReader(
                                new InputStreamReader(connection.getInputStream()));
            PrintWriter out = new PrintWriter(connection.getOutputStream());) {

            String line;
            try {
                while ((line = in.readLine()) != null) {
                    System.out.println(line);
                    out.println(line);
                    out.flush();
                    if (line.equals("Bye."))
                    break;
            } catch (IOException e){
                System.out.print("error in run");
            }
        }
    }

    public static void main(String[] args) throws IOException {
        try (ServerSocket sc = new ServerSocket(1111)) {
            while (true) {
                try (Socket dataSocket = sc.accept()) {
                    TestServer1 ts1=new TestServer1(dataSocket);
                    ts1.start();        
                }
            }
        }
    }
}

【讨论】:

    【解决方案4】:

    根据@Amir、@LFF 和@Abhijeet 的回答,我整理了以下版本,它可以工作。主要内容是:“Socket dataSocket = sc.accept()”不应作为资源放入“try()”;否则,主线程将关闭它。它应该由“run()”中的子线程关闭。

    感谢大家的帮助。

    public class ThreadedServer extends Thread {
        private Socket dataSocket;
    
        public ThreadedServer(Socket dataSocket) throws IOException {
            this.dataSocket = dataSocket;
        }
    
        @Override
        public void run() {
            String line;
            try (BufferedReader in = new BufferedReader(new InputStreamReader(
                    dataSocket.getInputStream()));
                    PrintWriter out = new PrintWriter(dataSocket.getOutputStream());) {
                while ((line = in.readLine()) != null) {
                    System.out.println(line);
                    out.println(line);
                    out.flush();
                    if (line.equals("Bye."))
                        break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    dataSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) throws IOException {
            try (ServerSocket sc = new ServerSocket(1111)) {
                while (true) {
                    try {
                        Socket dataSocket = sc.accept();
                        ThreadedServer ts = new ThreadedServer(dataSocket);
                        ts.start();
                    } finally {
                    }
                }
            }
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-16
      • 2015-07-09
      • 1970-01-01
      相关资源
      最近更新 更多