我只是在学习 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()");
}
}
}
在上面的示例中,我正在写入 a 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)
谁能解释这种不同的行为?