0

私はNIOを学んでいます.ブロッキングNIOがどのように中断されるかをテストするために私が書いた短い例を次に示します:

class TestBlockingNio {
    private static final boolean INTERRUPT_VIA_THREAD_INTERRUPT = true;

    /**
     * Prevent the socket from being GC'ed
     */
    static Socket socket;

    private static SocketChannel connect(final int port) {
        while (true) {
            try {
                final SocketChannel channel = SocketChannel.open(new InetSocketAddress(port));
                channel.configureBlocking(true);
                return channel;
            } catch (final IOException ioe) {
                try {
                    Thread.sleep(1000);
                } catch (final InterruptedException ie) {
                }
                continue;
            }
        }
    }

    private static byte[] newBuffer(final int length) {
        final byte buffer[] = new byte[length];
        for (int i = 0; i < length; i++) {
            buffer[i] = (byte) 'A';
        }
        return buffer;
    }

    public static void main(final String args[]) throws IOException, InterruptedException {
        final int portNumber = 10000;

        new Thread("Reader") {
            public void run() {
                try {
                    final ServerSocket serverSocket = new ServerSocket(portNumber);
                    socket = serverSocket.accept();
                    /*
                     * Fully ignore any input from the socket
                     */
                } catch (final IOException ioe) {
                    ioe.printStackTrace();
                }
            }

        }.start();

        final SocketChannel channel = connect(portNumber);

        final Thread main = Thread.currentThread();
        final Thread interruptor = new Thread("Inerruptor") {
            public void run() {
                System.out.println("Press Enter to interrupt I/O ");
                while (true) {
                    try {
                        System.in.read();
                    } catch (final IOException ioe) {
                        ioe.printStackTrace();
                    }
                    System.out.println("Interrupting...");
                    if (INTERRUPT_VIA_THREAD_INTERRUPT) {
                        main.interrupt();
                    } else {
                        try {
                            channel.close();
                        } catch (final IOException ioe) {
                            System.out.println(ioe.getMessage());
                        }
                    }
                }
            }
        };
        interruptor.setDaemon(true);
        interruptor.start();

        final ByteBuffer buffer = ByteBuffer.allocate(32768);    
        int i = 0;

        try {
            while (true) {
                buffer.clear();
                buffer.put(newBuffer(buffer.capacity()));
                buffer.flip();
                channel.write(buffer);
                System.out.print('X');
                if (++i % 80 == 0) {
                    System.out.println();
                    Thread.sleep(100);
                }
            }
        } catch (final ClosedByInterruptException cbie) {
            System.out.println("Closed via Thread.interrupt()");
        } catch (final AsynchronousCloseException ace) {
            System.out.println("Closed via Channel.close()");
        }
    }
}

上記の例では、 に書き込んSocketChannelでいますが、反対側から誰も読み取っていないため、最終的に書き込み操作がハングします。

この例は、JDK-1.6 で実行するとうまく機能し、次の出力が得られます。

    Press Enter to interrupt I/O 
    XXXX
    Interrupting...
    Closed via Thread.interrupt()

— 128k のデータのみが TCP ソケットのバッファに書き込まれたことを意味します。ただし、JDK-1.7 (1.7.0_25-b15 および 1.7.0-u40-b37) で実行すると、まったく同じコードがIOException:

    Press Enter to interrupt I/O 
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXX
    Exception in thread "main" java.io.IOException: Broken pipe
        at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
        at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
        at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
        at sun.nio.ch.IOUtil.write(IOUtil.java:65)
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:487)
        at com.example.TestBlockingNio.main(TestBlockingNio.java:109)

誰でもこの異なる動作を説明できますか?

4

1 に答える 1

0

どうやら、特定の JVM バージョンがサーバー ソケットをポートにバインドする方法に違いがあるようです。

サードパーティのプロセスが 127.0.0.1:10000 でリッスンしていることが判明しましたが、BindExceptionその間は発生しませんでしSocketChannel.open(new InetSocketAddress(10000))た。

同時に、1.6-VM は を使用してそれ自体に正常に接続していましたがen0、1.7-VM は を使用して外部プロセスに接続していましたlo0。プロセスが強制終了されると、JVM の動作はバージョン間で再び一貫したものになります。

于 2013-10-22T11:55:21.353 に答える