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

2020-04-25 10:48:00 +08:00
 amiwrong123

这个程序想说明,因同步 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 版本问题

2844 次点击
所在节点    Java
6 条回复
pursuer
2020-04-25 11:51:54 +08:00
应该和操作系统实现有关,我用 C 在 windows 下测试了下,stdin 在 read 堵塞的状态下,close 也会堵塞
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
2020-04-25 14:22:21 +08:00
@pursuer
这么说,有可能是哈。我还忘说自己的环境了,win10,jdk8.也许作者跑程序不是在 Windows 上跑的。
amiwrong123
2020-04-25 14:26:53 +08:00
@sioncheng
看了方法签名也是一脸懵啊,我都 System.in.close()了,那 System.in 这个 InputStream 此时感觉应该处于 the end of the stream is detected 的状态啊
sioncheng
2020-04-25 15:20:46 +08:00
@amiwrong123,应该感知到了,你输出 System.in.read 返回到结果看看,应该是-1,它并不一定要通过异常告诉调用者吧。
johnj
2020-04-25 16:49:15 +08:00
别用 IDE 执行,再试试

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/665899

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX