java BIO NIO AIO 理论篇
来源:互联网 发布:太原知达常青藤高中部 编辑:程序博客网 时间:2024/06/08 16:24
http://furturestrategist.iteye.com/blog/1463369
java中的IO主要源自于网络和本地文件
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO
在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。
NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。
在NIO的处理方式中,当一个请求来的话,开启线程进行处理,可能会等待后端应用的资源(JDBC连接等),其实这个线程就被阻塞了,当并发上来的话,还是会有BIO一样的问题。
HTTP/1.1出现后,有了Http长连接,这样除了超时和指明特定关闭的http header外,这个链接是一直打开的状态的,这样在NIO处理中可以进一步的进化,在后端资源中可以实现资源池或者队列,当请求来的话,开启的线程把请求和请求数据传送给后端资源池或者队列里面就返回,并且在全局的地方保持住这个现场(哪个连接的哪个请求等),这样前面的线程还是可以去接受其他的请求,而后端的应用的处理只需要执行队列里面的就可以了,这样请求处理和后端应用是异步的.当后端处理完,到全局地方得到现场,产生响应,这个就实现了异步处理。
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。
========http://xm-king.iteye.com/blog/766330
最近一直在忙着JAVA NIO的知识,花了一下午的时间,总算写出了一个可以运行的程序,废话少说,上代码!
import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Set;public class NIOServer {/*标识数字*/private int flag = 0;/*缓冲区大小*/private int BLOCK = 4096;/*接受数据缓冲区*/private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);/*发送数据缓冲区*/private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);private Selector selector;public NIOServer(int port) throws IOException {// 打开服务器套接字通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 服务器配置为非阻塞serverSocketChannel.configureBlocking(false);// 检索与此通道关联的服务器套接字ServerSocket serverSocket = serverSocketChannel.socket();// 进行服务的绑定serverSocket.bind(new InetSocketAddress(port));// 通过open()方法找到Selectorselector = Selector.open();// 注册到selector,等待连接serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("Server Start----8888:");}// 监听private void listen() throws IOException {while (true) {// 选择一组键,并且相应的通道已经打开selector.select();// 返回此选择器的已选择键集。Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();iterator.remove();handleKey(selectionKey);}}}// 处理请求private void handleKey(SelectionKey selectionKey) throws IOException {// 接受请求ServerSocketChannel server = null;SocketChannel client = null;String receiveText;String sendText;int count=0;// 测试此键的通道是否已准备好接受新的套接字连接。if (selectionKey.isAcceptable()) {// 返回为之创建此键的通道。server = (ServerSocketChannel) selectionKey.channel();// 接受到此通道套接字的连接。// 此方法返回的套接字通道(如果有)将处于阻塞模式。client = server.accept();// 配置为非阻塞client.configureBlocking(false);// 注册到selector,等待连接client.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {// 返回为之创建此键的通道。client = (SocketChannel) selectionKey.channel();//将缓冲区清空以备下次读取receivebuffer.clear();//读取服务器发送来的数据到缓冲区中count = client.read(receivebuffer);if (count > 0) {receiveText = new String( receivebuffer.array(),0,count);System.out.println("服务器端接受客户端数据--:"+receiveText);client.register(selector, SelectionKey.OP_WRITE);}} else if (selectionKey.isWritable()) {//将缓冲区清空以备下次写入sendbuffer.clear();// 返回为之创建此键的通道。client = (SocketChannel) selectionKey.channel();sendText="message from server--" + flag++;//向缓冲区中输入数据sendbuffer.put(sendText.getBytes()); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位sendbuffer.flip();//输出到通道client.write(sendbuffer);System.out.println("服务器端向客户端发送数据--:"+sendText);client.register(selector, SelectionKey.OP_READ);}}/** * @param args * @throws IOException */public static void main(String[] args) throws IOException {// TODO Auto-generated method stubint port = 8888;NIOServer server = new NIOServer(port);server.listen();}}
import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Iterator;import java.util.Set;public class NIOClient {/*标识数字*/private static int flag = 0;/*缓冲区大小*/private static int BLOCK = 4096;/*接受数据缓冲区*/private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);/*发送数据缓冲区*/private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);/*服务器端地址*/private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("localhost", 1111);public static void main(String[] args) throws IOException {// TODO Auto-generated method stub// 打开socket通道SocketChannel socketChannel = SocketChannel.open();// 设置为非阻塞方式socketChannel.configureBlocking(false);// 打开选择器Selector selector = Selector.open();// 注册连接服务端socket动作socketChannel.register(selector, SelectionKey.OP_CONNECT);// 连接socketChannel.connect(SERVER_ADDRESS);// 分配缓冲区大小内存Set<SelectionKey> selectionKeys;Iterator<SelectionKey> iterator;SelectionKey selectionKey;SocketChannel client;String receiveText;String sendText;int count=0;while (true) {//选择一组键,其相应的通道已为 I/O 操作准备就绪。//此方法执行处于阻塞模式的选择操作。selector.select();//返回此选择器的已选择键集。selectionKeys = selector.selectedKeys();//System.out.println(selectionKeys.size());iterator = selectionKeys.iterator();while (iterator.hasNext()) {selectionKey = iterator.next();if (selectionKey.isConnectable()) {System.out.println("client connect");client = (SocketChannel) selectionKey.channel();// 判断此通道上是否正在进行连接操作。// 完成套接字通道的连接过程。if (client.isConnectionPending()) {client.finishConnect();System.out.println("完成连接!");sendbuffer.clear();sendbuffer.put("Hello,Server".getBytes());sendbuffer.flip();client.write(sendbuffer);}client.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {client = (SocketChannel) selectionKey.channel();//将缓冲区清空以备下次读取receivebuffer.clear();//读取服务器发送来的数据到缓冲区中count=client.read(receivebuffer);if(count>0){receiveText = new String( receivebuffer.array(),0,count);System.out.println("客户端接受服务器端数据--:"+receiveText);client.register(selector, SelectionKey.OP_WRITE);}} else if (selectionKey.isWritable()) {sendbuffer.clear();client = (SocketChannel) selectionKey.channel();sendText = "message from client--" + (flag++);sendbuffer.put(sendText.getBytes()); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位sendbuffer.flip();client.write(sendbuffer);System.out.println("客户端向服务器端发送数据--:"+sendText);client.register(selector, SelectionKey.OP_READ);}}selectionKeys.clear();}}}
个人感觉,JAVA NIO的操作时麻烦了不少,但是无疑这样做效率会得到很大的提升。
- java BIO NIO AIO 理论篇
- java BIO NIO AIO 理论篇
- java BIO NIO AIO理论篇
- java BIO NIO AIO 理论篇
- java BIO NIO AIO 理论篇
- java BIO NIO AIO 理论篇
- java BIO NIO AIO的理论
- java BIO NIO AIO
- Java BIO、NIO、AIO
- java BIO NIO AIO
- Java BIO/NIO/AIO
- java bio nio aio
- java nio aio bio
- java nio bio aio
- JAVA AIO BIO NIO
- Java BIO、NIO、AIO
- Java bio nio aio
- Java BIO、NIO、AIO
- Linux内置的审计跟踪工具:last命令
- bash shell 下的环境变量
- Hibernate 一对多注解 实例
- Entity Framework DbContext对一个Entity 进行更新。
- win7系统中C盘空间缩水的有效处理方法
- java BIO NIO AIO 理论篇
- 如何理解const char*, char const*, char*const等
- 从MAC上生成pem文件用于推送
- Linux的系统性能监测参数获取方法介绍
- phpcms建站还是不错的,新站运行两周,效果显著
- Yii中CActiveRecord有relation的时候分页
- C# WPF 接收启动命令行参数
- HDU 1713 相遇周期
- 实现UISCrollView循环滚动