私は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)
誰でもこの異なる動作を説明できますか?