为什么多线程我的单线程简单echo服务器导致它停止工作



这个单线程回声服务器工作得很好。

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

下面是stacktrace

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)

Java 7: Try with resources

使用Java 7,您可以在尝试中创建一个或多个"资源"声明。"资源"是实现java.lang.AutoCloseable接口。这个资源是自动关闭并结束try块。

  • 查看更多信息:http://www.vineetmanohar.com/2011/03/java-7-try-with-auto-closable-resources/#sthash.cnvRzGIZ.dpuf
从javadoc:

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

所以这可能是原因,当它超出作用域时,你的流会自动关闭。

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()方法中关闭流

试试下面这个版本——它没有经过测试。但是正如我在评论中所说的,我认为您在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();        
                }
            }
        }
    }
}

根据@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 {
                }
            }
        }
    }

最新更新