1
http://www.jdon.com/concurrent/nio%D4%AD%C0%ED%D3%A6%D3%C3.htm
http://tenyears.iteye.com/blog/40489
http://hi.baidu.com/lovemywolf/blog/item/a6b0ebf2ff5d8f06b17ec531.html
http://www.iteye.com/topic/834447
同步和异步仅仅是关于所关注的消息如何通知的机制,而不是处理消息的机制. 同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者
http://blog.sina.com.cn/s/blog_46fc12960100dosb.html
http://www.blogjava.net/pengpenglin/archive/2010/03/10/315053.html
http://atell.iteye.com/blog/977256
http://blog.csdn.net/haoel/article/details/2224055
http://blog.csdn.net/haoel/article/details/2224069
nio的精髓是多路复用,将多个线程阻塞等候io就绪,转化为一个线程阻塞等候io就绪,io就绪异步触发等待线程。
it's no longer necessary to dedicate a thread to each socket connection (and suffer the context-switching
overhead of managing large numbers of threads).
不错的心得
http://hi.baidu.com/personnel/blog/item/0fb7b31b7a7bec028618bf8f.html
nio使用的reactor模式,反应器模式。实现多路复用和事件派发,将io就绪事件派发给不同的处理器处理。
而proactor模式与之类似,不同点是proactor模式是将io完成事件派发给处理器处理。
将nio发扬光大的开源框架是mina,下面是主流java通信框架的测评
http://liaoyixun.iteye.com/blog/168065
aio出炉了
http://www.iteye.com/topic/472333
http://www.4ucode.com/Study/Topic/1101177
实践了accept事件
java nio建议只使用一个selector,然后用不同的线程池去处理io就绪事件。对于多核系统,多个selector带来的好处不多,但却加大复杂性。
file lock是和文件相关的,对不同进程有效。locks are associated with processes and not with Java threads.
Pipes can be used only to pass data within the same JVM,the advantage of using pipes is encapsulation. Producer and consumer threads can be written to the common Channel API.
If you pass a nondirect ByteBuffer object to a channel for write, the channel may implicitly do the following on each call:
1. Create a temporary direct ByteBuffer object.
2. Copy the content of the nondirect buffer to the temporary buffer.
3. Perform the low-level I/O operation using the temporary buffer.
4. The temporary buffer object goes out of scope and is eventually garbage
collected.
表面上步骤多了,会对性能有所影响,但是影响不大,虚拟机对这个有做优化,所以在大部分情况下可以使用bytebuffer.
Mapped buffers are byte buffers with data elements stored in a file and are accessed via memory mapping。Mapped buffers are always direct and can be created only from a FileChannel object.
一个echo服务例子
tip: 1 对一个通道多次注册感兴趣事件,只会以最后一个为准,即每次注册只保留最后一个;
2 nio一般用bytebuffer来作为缓存区,需要特别注意缓存区的各个游标含义,读写切换记得flip();
3 一般来说较少注册write事件,因为一个通道基本上90%以上的时间都是writable的,注册这个事件会导致无意义的cpu消耗;
4 java.nio.channels.Selector.select()可能返回0,不阻塞,有潜在的死循环危险。需要了解发生0的原因??
客户端
5 java.io.OutputStream.write(byte[])直接发送到接收方。
public static int PORT_NUMBER = 80; private ByteBuffer buffer=ByteBuffer.allocate(1024*10); @Test public void testClient() throws Exception { SocketChannel channel = SocketChannel.open(); // Create a new Selector for use below Selector selector = Selector.open(); // Set the port the server channel will listen to // Set nonblocking mode for the listening socket channel.configureBlocking(false); // Register the ServerSocketChannel with the Selector channel.register(selector, SelectionKey.OP_CONNECT); SocketAddress server=new InetSocketAddress("127.0.0.1", PORT_NUMBER); channel.connect(server); while (true) { // This may block for a long time. Upon returning, the // selected set contains keys of the ready channels. int n = selector.select(); if (n == 0) { continue; // nothing to do } // Get an iterator over the set of selected keys Iterator it = selector.selectedKeys().iterator(); // Look at each key in the selected set while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); // Is a new connection coming in? // Is there data to read on this channel? if (key.isReadable()) { print(key); } if (key.isConnectable()) { SocketChannel client = (SocketChannel) key .channel(); client.finishConnect(); registerChannel(selector, client, SelectionKey.OP_READ); new SayHello(client).start(); } if (key.isWritable()) { System.out.println("can write"); } // Remove key from selected set; it's been handled it.remove(); } } } private void print(SelectionKey key) throws IOException{ SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer bb=ByteBuffer.allocate(1204); socketChannel.read(bb); bb.flip(); System.out.println(new String(bb.array())); } private class SayHello extends Thread{ private SocketChannel channel; public SayHello(SocketChannel socketChannel){ this.channel=socketChannel; } @Override public void run() { for (int i = 0; i < 100; i++) { try { buffer.clear(); buffer.put((i+"-Hi there!\r\n").getBytes()); buffer.flip(); channel.write(buffer); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } } } } protected void registerChannel(Selector selector, SelectableChannel channel, int ops) throws Exception { if (channel == null) { return; // could happen } // Set the new channel nonblocking channel.configureBlocking(false); // Register it with the selector channel.register(selector, ops); }
服务端:
public static int PORT_NUMBER = 80; @Test public void testServer() throws Exception { int port = PORT_NUMBER; System.out.println("Listening on port " + port); // Allocate an unbound server socket channel ServerSocketChannel serverChannel = ServerSocketChannel.open(); // Get the associated ServerSocket to bind it with ServerSocket serverSocket = serverChannel.socket(); // Create a new Selector for use below Selector selector = Selector.open(); // Set the port the server channel will listen to serverSocket.bind(new InetSocketAddress(port)); // Set nonblocking mode for the listening socket serverChannel.configureBlocking(false); // Register the ServerSocketChannel with the Selector serverChannel.register(selector, SelectionKey.OP_ACCEPT); while (true) { // This may block for a long time. Upon returning, the // selected set contains keys of the ready channels. int n = selector.select(); if (n == 0) { continue; // nothing to do } // Get an iterator over the set of selected keys Iterator it = selector.selectedKeys().iterator(); // Look at each key in the selected set while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); // Is a new connection coming in? if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key .channel(); SocketChannel channel = server.accept(); registerChannel(selector, channel, SelectionKey.OP_READ); } // Is there data to read on this channel? if (key.isReadable()) { echo(key); } // Remove key from selected set; it's been handled it.remove(); } } } private void echo(SelectionKey key) throws IOException{ SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer bb=ByteBuffer.allocate(1204); socketChannel.read(bb); bb.flip(); socketChannel.write(bb); } protected void registerChannel(Selector selector, SelectableChannel channel, int ops) throws Exception { if (channel == null) { return; // could happen } // Set the new channel nonblocking channel.configureBlocking(false); // Register it with the selector channel.register(selector, ops); }