V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
amiwrong123
V2EX  ›  Java

因为 System.in.read()而阻塞的线程,无法通过 System.in.close()唤醒?

  •  
  •   amiwrong123 · 2020-04-25 10:48:00 +08:00 · 2742 次点击
    这是一个创建于 1461 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个程序想说明,因同步 IO 资源而阻塞的线程,可以通过关闭 IO 资源而停止阻塞。

    //: concurrency/CloseResource.java
    // Interrupting a blocked task by
    // closing the underlying resource.
    // {RunByHand}
    import java.net.*;
    import java.util.concurrent.*;
    import java.io.*;
    import static net.mindview.util.Print.*;
    
    class IOBlocked implements Runnable {
        private InputStream in;
        public IOBlocked(InputStream is) { in = is; }
        public void run() {
            try {
                print("Waiting for read():");
                in.read();
            } catch(Exception e) {
                e.printStackTrace();  //这句是我加的
                if(Thread.currentThread().isInterrupted()) {
                    print("Interrupted from blocked I/O");
                } else {
                    throw new RuntimeException(e);
                }
            }
            print("Exiting IOBlocked.run()");
        }
    }
    
    public class CloseResource {
        public static void main(String[] args) throws Exception {
            ExecutorService exec = Executors.newCachedThreadPool();
            ServerSocket server = new ServerSocket(8080);
            InputStream socketInput =
                    new Socket("localhost", 8080).getInputStream();
            exec.execute(new IOBlocked(socketInput));
            exec.execute(new IOBlocked(System.in));
            TimeUnit.MILLISECONDS.sleep(100);
            print("Shutting down all threads");
            exec.shutdownNow();
            TimeUnit.SECONDS.sleep(1);
            print("Closing " + socketInput.getClass().getName());
            socketInput.close(); // Releases blocked thread
            TimeUnit.SECONDS.sleep(1);
            print("Closing " + System.in.getClass().getName());
            System.in.close(); // Releases blocked thread
        }
    }/* Output: (85% match)
    Waiting for read():
    Waiting for read():
    Shutting down all threads
    Closing java.net.SocketInputStream
    Interrupted from blocked I/O
    Exiting IOBlocked.run()
    Closing java.io.BufferedInputStream
    Exiting IOBlocked.run()            //书中的打印结果就有这句,而我的没有
    *///:~
    

    打印结果:

    Waiting for read():
    Waiting for read():
    Shutting down all threads
    Closing java.net.SocketInputStream
    java.net.SocketException: Socket closed
    	at java.net.SocketInputStream.socketRead0(Native Method)
    	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    	at java.net.SocketInputStream.read(SocketInputStream.java:170)
    	at java.net.SocketInputStream.read(SocketInputStream.java:141)
    	at java.net.SocketInputStream.read(SocketInputStream.java:223)
    	at IOBlocked.run(Interrupting.java:24)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    	at java.lang.Thread.run(Thread.java:745)
    Interrupted from blocked I/O
    Exiting IOBlocked.run()
    Closing java.io.BufferedInputStream
    

    执行后,程序无法结束,从打印结果也可以看出,第二个线程还是处于运行中。这个例子来自 java 编程思想,书中说到,两个线程都会因为资源的关闭而结束.

    所以,为什么因为 System.in.read()而阻塞的线程,无法通过 System.in.close()唤醒(可能是以抛出异常的方式)?明明书中都说可以,难道是 java 版本问题

    6 条回复    2020-04-25 16:49:15 +08:00
    pursuer
        1
    pursuer  
       2020-04-25 11:51:54 +08:00
    应该和操作系统实现有关,我用 C 在 windows 下测试了下,stdin 在 read 堵塞的状态下,close 也会堵塞
    sioncheng
        2
    sioncheng  
       2020-04-25 12:41:55 +08:00
    看方法签名来解释?应该只是是 jvm 实现者的一些考虑和选择吧。毕竟操作系统层面的 socket api ( c/api ),也不是通过 exception 来表示 read 一个 closed 的 socket 。
    /**
    * Reads the next byte of data from the input stream. The value byte is
    * returned as an <code>int</code> in the range <code>0</code> to
    * <code>255</code>. If no byte is available because the end of the stream
    * has been reached, the value <code>-1</code> is returned. This method
    * blocks until input data is available, the end of the stream is detected,
    * or an exception is thrown.
    *
    * <p> A subclass must provide an implementation of this method.
    *
    * @return the next byte of data, or <code>-1</code> if the end of the
    * stream is reached.
    * @exception IOException if an I/O error occurs.
    */
    public abstract int read() throws IOException;
    amiwrong123
        3
    amiwrong123  
    OP
       2020-04-25 14:22:21 +08:00
    @pursuer
    这么说,有可能是哈。我还忘说自己的环境了,win10,jdk8.也许作者跑程序不是在 Windows 上跑的。
    amiwrong123
        4
    amiwrong123  
    OP
       2020-04-25 14:26:53 +08:00
    @sioncheng
    看了方法签名也是一脸懵啊,我都 System.in.close()了,那 System.in 这个 InputStream 此时感觉应该处于 the end of the stream is detected 的状态啊
    sioncheng
        5
    sioncheng  
       2020-04-25 15:20:46 +08:00
    @amiwrong123,应该感知到了,你输出 System.in.read 返回到结果看看,应该是-1,它并不一定要通过异常告诉调用者吧。
    johnj
        6
    johnj  
       2020-04-25 16:49:15 +08:00
    别用 IDE 执行,再试试
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3039 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:31 · PVG 08:31 · LAX 17:31 · JFK 20:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.