利不百不变法,功不十不易器
为什么会出现nio,之前的io有什么问题?
请先看
说说nio1
nio类图例如以下
package io; //: io/GetChannel.java // Getting channels from streams import java.nio.*; import java.nio.channels.*; import java.io.*; public class GetChannel { private static final int BSIZE = 1024; public static void main(String[] args) throws Exception { // Write a file: FileChannel fc = new FileOutputStream("data.txt").getChannel(); fc.write(ByteBuffer.wrap("Some text ".getBytes())); fc.close(); // Add to the end of the file: fc = new RandomAccessFile("data.txt", "rw").getChannel(); fc.position(fc.size()); // Move to the end fc.write(ByteBuffer.wrap("Some more".getBytes())); fc.close(); // Read the file: fc = new FileInputStream("data.txt").getChannel(); ByteBuffer buff = ByteBuffer.allocate(BSIZE); fc.read(buff); buff.flip(); while(buff.hasRemaining()) System.out.print((char)buff.get()); } } /* Output: Some text Some more *///:~
package io; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.concurrent.*; import java.io.*; public class FileLocking { public static void main(String[] args) throws Exception { FileOutputStream fos= new FileOutputStream("file.txt"); FileLock fl = fos.getChannel().tryLock(); if(fl != null) { System.out.println("Locked File"); FileChannel fc =fos.getChannel(); fc.write(ByteBuffer.wrap("Some textssss".getBytes())); TimeUnit.MILLISECONDS.sleep(1000); fl.release(); System.out.println("Released Lock"); } fos.close(); } } /* Output: Locked File Released Lock *///:~
package io; import java.io.IOException; import java.io.RandomAccessFile; import java.net.URL; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; /** * 測试NIO中的文件锁:三个线程争抢文件锁。获得锁后向文件里写数据,然后再释放文件锁。* * @author aofeng <a href="mailto:aofengblog@163.com>aofengblog@163.com</a> */ public class LockTest implements Runnable { public void run() { Thread curr = Thread.currentThread(); System.out.println("Current executing thread is " + curr.getName()); URL url = LockTest.class.getClassLoader().getResource("file.txt"); //路径问题 //http://www.cnblogs.com/rongxh7/archive/2010/04/22/1718178.html //http://www.cnblogs.com/yejg1212/p/3270152.html RandomAccessFile raf = null; FileChannel fc = null; FileLock lock = null; try { //就是这里的路径问题, 为什么要替换%20 去上面的资料里看 raf = new RandomAccessFile(url.getPath().replaceAll("%20"," "), "rw"); fc = raf.getChannel(); System.out.println(curr.getName() + " ready"); // 轮流获得文件独占锁。 while (true) { try { lock = fc.lock(); break; } catch (OverlappingFileLockException e) { Thread.sleep(1 * 1000); } } if (null != lock) { System.out.println(curr.getName() + " get filelock success"); fc.position(fc.size()); fc.write(ByteBuffer.wrap((curr.getName() + " write data. ") .getBytes())); } else { System.out.println(curr.getName() + " get filelock fail"); } fc.close(); raf.close(); } catch (Exception e) { e.printStackTrace(); } finally { // 注意:要先释放锁,再关闭通道。 if (null != lock && lock.isValid()) { try { lock.release(); System.out.println(curr.getName() + " release filelock"); } catch (IOException e) { e.printStackTrace(); } } } } /** * @param args */ public static void main(String[] args) { Thread t1 = new Thread(new LockTest()); t1.setName("t1"); Thread t2 = new Thread(new LockTest()); t2.setName("t2"); Thread t3 = new Thread(new LockTest()); t3.setName("t3"); t1.start(); t2.start(); t3.start(); } }
ok如今我们看看在网络中,nio是在怎么运作的
public static void acceptConnections( int port) throws Exception { // 打开一个 Selector Selector acceptSelector = SelectorProvider.provider().openSelector(); // 创建一个 ServerSocketChannel 。这是一个 SelectableChannel 的子类 ServerSocketChannel ssc = ServerSocketChannel.open(); // 将其设为 non-blocking 状态,这样才干进行非堵塞 IO 操作 ssc.configureBlocking( false ); // 给 ServerSocketChannel 相应的 socket 绑定 IP 和端口 InetAddress lh = InetAddress.getLocalHost(); InetSocketAddress isa = new InetSocketAddress(lh, port); ssc.socket().bind(isa); // 将 ServerSocketChannel 注冊到 Selector 上,返回相应的 SelectionKey ssc.register(acceptSelector, SelectionKey.OP_ACCEPT); int keysAdded = 0; // 用 select() 函数来监控注冊在 Selector 上的 SelectableChannel // 返回值代表了有多少 channel 能够进行 IO 操作 (ready for IO) while ((keysAdded = acceptSelector.select()) > 0) { // selectedKeys() 返回一个 SelectionKey 的集合, // 当中每一个 SelectionKey 代表了一个能够进行 IO 操作的 channel 。// 一个 ServerSocketChannel 能够进行 IO 操作意味着有新的 TCP 连接连入了 Set<SelectionKey> readyKeys = acceptSelector.selectedKeys(); Iterator<SelectionKey> i = readyKeys.iterator(); while (i.hasNext()) { SelectionKey sk = (SelectionKey) i.next(); // 须要将处理过的 key 从 selectedKeys 这个集合中删除 i.remove(); // 从 SelectionKey 得到相应的 channel ServerSocketChannel nextReady =(ServerSocketChannel) sk.channel(); // 接受新的 TCP 连接 Socket s = nextReady.accept().socket(); // 把当前的时间写到这个新的 TCP 连接中 PrintWriter out =new PrintWriter(s.getOutputStream(), true ); Date now = new Date(); out.println(now); // 关闭连接 out.close(); } } }
一般来说 I/O 模型能够分为:同步堵塞,同步非堵塞,异步堵塞,异步非堵塞 四种IO模型
同步堵塞 IO : 我们在上一篇文章nio1里面说的就是这个
在此种方式下,用户进程在发起一个 IO 操作以后,必须等待 IO 操作的完毕,仅仅有当真正完毕了 IO 操作以后,用户进程才干执行。
JAVA传统的 IO 模型属于此种方式!
我去找小明借书 小明開始在自己的家里找 我什么事情都不干 就在他家里等 他找到后给我 这就是同步堵塞
同步非堵塞 IO: 这篇文章说nio就是 指这个
在此种方式下,用户进程发起一个 IO 操作以后 边可 返回做其他事情,可是用户进程须要时不时的询问 IO 操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的 CPU 资源浪费。当中眼下 JAVA 的 NIO 就属于同步非堵塞 IO 。
我去找小明借书 小明開始找 我先去玩 过一会来看 假设没有找到 那就继续去玩 等会再来看 找到了 那就一切OK
异步堵塞 IO : 还没有提到
此种方式下是指应用发起一个 IO 操作以后,不等待内核 IO 操作的完毕,等内核完毕 IO 操作以后会通知应用程序,这事实上就是同步和异步最关键的差别,同步必须等待或者主动的去询问 IO 是否完毕,那么为什么说是堵塞的呢?由于此时是通过 select 系统调用来完毕的,而 select 函数本身的实现方式是堵塞的,而採用 select 函数有个优点就是它能够同一时候监听多个文件句柄。从而提高系统的并发性!
我去找小明借书 小明開始找 我先去玩 他找到书后 会给我送来
异步非堵塞 IO:
在此种模式下,用户进程仅仅须要发起一个 IO 操作然后马上返回,等 IO 操作真正的完毕以后,应用程序会得到 IO 操作完毕的通知,此时用户进程仅仅须要对数据进行处理就好了,不须要进行实际的 IO 读写操作。由于 真正的 IO读取或者写入操作已经由 内核完毕了。眼下 Java 中还没有支持此种 IO 模型。
关于异步非堵塞 IO: 请參考 http://janeky.iteye.com/blog/1073695http://www.blogjava.net/19851985lili/articles/93524.html
http://www.zhihu.com/question/27991975/answer/69041973
深入分析java web内幕 许令波 第二章 深入分析java/io的工作机制
http://janeky.iteye.com/blog/1073695
原文:http://www.cnblogs.com/mengfanrong/p/5122355.html