利不百不变法,功不十不易器
为什么会出现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