如何在Java中的阻塞读取操作中停止线程等待?
我有一个执行以下代码的线程:
public void run() {    try {
        int n = 0;
        byte[] buffer = new byte[4096];
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
            out.flush();
        }
    } catch (IOException e) {
        System.out.println(e);
    }
}
哪里in是System.in。如何才能优雅地停止此类线程?关闭System.in或使用均Thread.interrupt无效。
回答:
这是因为读取System.in(InputStream)是一项阻塞操作。
在这里看是否可以从InputStream读取超时?
这是一种从System.in获取NIO FileChannel并使用超时检查数据可用性的方法,这是问题中所述问题的特例。在控制台上运行它,不要键入任何输入,然后等待结果。它已在Windows和Linux上的Java 6下成功测试。
import java.io.FileInputStream;import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
public class Main {
    static final ByteBuffer buf = ByteBuffer.allocate(4096);
    public static void main(String[] args) {
        long timeout = 1000 * 5;
        try {
            InputStream in = extract(System.in);
            if (! (in instanceof FileInputStream))
                throw new RuntimeException(
                        "Could not extract a FileInputStream from STDIN.");
            try {
                int ret = maybeAvailable((FileInputStream)in, timeout);
                System.out.println(
                        Integer.toString(ret) + " bytes were read.");
            } finally {
                in.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /* unravels all layers of FilterInputStream wrappers to get to the
     * core InputStream
     */
    public static InputStream extract(InputStream in)
            throws NoSuchFieldException, IllegalAccessException {
        Field f = FilterInputStream.class.getDeclaredField("in");
        f.setAccessible(true);
        while( in instanceof FilterInputStream )
            in = (InputStream)f.get((FilterInputStream)in);
        return in;
    }
    /* Returns the number of bytes which could be read from the stream,
     * timing out after the specified number of milliseconds.
     * Returns 0 on timeout (because no bytes could be read)
     * and -1 for end of stream.
     */
    public static int maybeAvailable(final FileInputStream in, long timeout)
            throws IOException, InterruptedException {
        final int[] dataReady = {0};
        final IOException[] maybeException = {null};
        final Thread reader = new Thread() {
            public void run() {                
                try {
                    dataReady[0] = in.getChannel().read(buf);
                } catch (ClosedByInterruptException e) {
                    System.err.println("Reader interrupted.");
                } catch (IOException e) {
                    maybeException[0] = e;
                }
            }
        };
        Thread interruptor = new Thread() {
            public void run() {
                reader.interrupt();
            }
        };
        reader.start();
        for(;;) {
            reader.join(timeout);
            if (!reader.isAlive())
                break;
            interruptor.start();
            interruptor.join(1000);
            reader.join(1000);
            if (!reader.isAlive())
                break;
            System.err.println("We're hung");
            System.exit(1);
        }
        if ( maybeException[0] != null )
            throw maybeException[0];
        return dataReady[0];
    }
}
有趣的是,在NetBeans 6.5中而不是在控制台中运行程序时,超时根本不起作用,并且实际上必须调用System.exit()来杀死僵尸线程。发生的情况是中断线程在对reader.interrupt()的调用中阻塞了(!)。另外,另一个测试程序(此处未显示)尝试关闭通道,但这也不起作用。
以上是 如何在Java中的阻塞读取操作中停止线程等待? 的全部内容, 来源链接: utcz.com/qa/402923.html








