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

时间:2014-07-15 03:48:12

标签: java multithreading

这个单线程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线程并启动它。没什么特别的。但不知何故,当客户端连接到此服务器时,"Stream close"中会抛出run()异常并打印"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)

4 个答案:

答案 0 :(得分:1)

  

Java 7:尝试使用资源

     

使用Java 7,您可以在try中创建一个或多个“资源”   声明。 “资源”是实现这一目标的东西   java.lang.AutoCloseable接口。这个资源就是   自动关闭并尝试阻止结束。

来自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

所以可能这可能是理由,当你的视频超出范围时你的视频会自动关闭。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

请尝试以下版本 - 未经测试。但正如我在评论中所说,我相信你在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();        
                }
            }
        }
    }
}

答案 3 :(得分:0)

基于@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 {
                }
            }
        }

    }