NIO学习笔记五

来源:互联网 发布:淘宝修改送货地址 编辑:程序博客网 时间:2024/05/14 22:04

文件锁定

    要获取文件的一部分上的锁,需要调用FileChannel上的locak()方法。注意,如果要获取一个排它锁,您必须以写方式打开文件。

    第二行中调用lock方法来获取锁,position参数表示锁的起始位置,size表示锁的范围,shared是一个boolean值,true表示是一个共享锁,false表示是一个排它锁。

FileChannel channel = out.getChannel();FileLock lock = channel.lock(position, size, shared);lock.release();

异步I/O

    通常程序中调用read()方法时,程序会阻塞直至有可供读取的数据。同样,调用write()将会阻塞直至数据能够写入。而异步I/O是一种没有阻塞的读写数据的方法,我们将感兴趣的特性的I/O事件注册到选择器上面,当这些事件发生时,系统将会告诉我们。异步 I/O 的一个优势在于,它允许您同时根据大量的输入和输出执行 I/O。同步程序常常要求助于轮询,或者创建许许多多的线程以处理大量的连接。使用异步 I/O,您可以监听任何数量的通道上的事件,不用轮询,也不用额外的线程。

    异步I/O中的核心对象是Selector,表示一个选择器,它就是我们注册感兴趣I/O事件的地方,当这些事件发生,这个选择器就会通知我们。每次返回主循环,我们都要调用 select 的 Selector()方法,并取得一组 SelectionKey。每个键代表一个 I/O 事件。我们处理事件,从选定的键集中删除 SelectionKey,然后返回主循环的顶部。

public class MultiPortEcho {private int ports[];//用于保存端口号private ByteBuffer echoBuffer = ByteBuffer.allocate(1024);public MultiPortEcho(int ports[]) throws IOException {this.ports = ports;go();}private void go() throws IOException {//创建一个选择器对象Selector selector = Selector.open();//在每个端口上开启监听,绑定端口号,并注册到选择器上for (int i = 0; i < ports.length; ++i) {ServerSocketChannel ssc = ServerSocketChannel.open();//设置为false表示非阻塞ssc.configureBlocking(false);ServerSocket ss = ssc.socket();InetSocketAddress address = new InetSocketAddress(ports[i]);ss.bind(address);//将新打开的 ServerSocketChannels 注册到 Selector上//SelectionKey 代表这个通道在此 Selector 上的这个注册。//当某个 Selector 通知您某个传入事件时,它是通过提供对应于该事件的 SelectionKey 来进行的。//SelectionKey 还可以用于取消通道的注册。SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);System.out.println("Going to listen on " + ports[i]);}while (true) {//这个方法会阻塞,直到至少有一个已注册的事件发生。//当一个或者更多的事件发生时, select() 方法将返回所发生的事件的数量。int num = selector.select();Set selectedKeys = selector.selectedKeys();Iterator it = selectedKeys.iterator();while (it.hasNext()) {SelectionKey key = (SelectionKey) it.next();if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {//接受新连接ServerSocketChannel ssc = (ServerSocketChannel) key.channel();SocketChannel sc = ssc.accept();//将新连接设置为非阻塞sc.configureBlocking(false);//将连接注册到选择器上, OP_READ 参数表示将 SocketChannel注册用于读取而不是接受新连接。SelectionKey newKey = sc.register(selector, SelectionKey.OP_READ);//将处理过的 SelectionKey 从选定的键集合中删除//如果我们没有删除处理过的键,那么它仍然会在主集合中以一个激活的键出现,这会导致我们尝试再次处理它.it.remove();System.out.println("Got connection from " + sc);} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {//接收数据SocketChannel sc = (SocketChannel) key.channel();int bytesEchoed = 0;while (true) {echoBuffer.clear();int r = sc.read(echoBuffer);if (r <= 0) {break;}echoBuffer.flip();sc.write(echoBuffer);bytesEchoed += r;}System.out.println("Echoed " + bytesEchoed + " from " + sc);it.remove();}}}}public static void main(String args[]) throws Exception {if (args.length <= 0) {System.err.println("Usage: java MultiPortEcho port [port port ...]");System.exit(1);}int ports[] = new int[args.length];for (int i = 0; i < args.length; ++i) {ports[i] = Integer.parseInt(args[i]);}new MultiPortEcho(ports);}}



0 0
原创粉丝点击