Java 中java实现一个阻塞队列非阻塞通信需要哪些

查看:4009|回复:1
各位大虾 帮忙分析下用 NIO 实现非阻塞通信的原理
是否用的是状态模式& &
通过不同状态采取不同行为& &
接着行为处理完信息后又重置状态
达到不间断的通信& &
就像并发程序(不断交替运行的线程)
来个流程图那就太Wonderful了
说NIO的非阻塞原理之前,我们需要先说一下传统的io。传统的IO是按字节传输的,即每次传输一个字节。为了提高数据传输效率,引进了带缓冲区得输入输出模式,这样每次就可以传输大量的字节数,但是,会导致在读(写)缓冲区没有满的情况下,程序会一直等待,直到满或者关闭流才能读取(写入)。这样导致程序阻塞,降低了程序的执行效率。
如今的NIO的实现并非如此,他的传输是块传输,即每次传输一个块,一个块中可以包含大量的字节数,这样可以有效的提高传输速率而不会导致程序阻塞。如果你懂得设计模式,他的实现原理跟Observer模式类似,即观察者模式。我给你贴一段程序代码,你就能很好的理解。
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.net.*;
import java.util.*;
Administrator
* @version
public class NBTest {
  /** Creates new NBTest */
  public NBTest()
  public void startServer() throws Exception
  int channels = 0;
  int nKeys = 0;
  int currentSelector = 0;
  //使用Selector
  Selector selector = Selector.open();
  //建立Channel 并绑定到9000端口
  ServerSocketChannel ssc = ServerSocketChannel.open();
  InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(),9000);
  ssc.socket().bind(address);
  //使设定non-blocking的方式。
  ssc.configureBlocking(false);
  //向Selector注册Channel及我们有兴趣的事件
  SelectionKey s = ssc.register(selector, SelectionKey.OP_ACCEPT);
  printKeyInfo(s);
  while(true) //不断的轮询
    debug(&NBTest: Starting select&);
    //Selector通过select方法通知我们我们感兴趣的事件发生了。
    nKeys = selector.select();
    //如果有我们注册的事情发生了,它的传回值就会大于0
    if(nKeys & 0)
      debug(&NBTest: Number of keys after select operation: & +nKeys);
      //Selector传回一组SelectionKeys
      //我们从这些key中的channel()方法中取得我们刚刚注册的channel。
      Set selectedKeys = selector.selectedKeys();
      Iterator i = selectedKeys.iterator();
      while(i.hasNext())
      {
         s = (SelectionKey) i.next();
         printKeyInfo(s);
         debug(&NBTest: Nr Keys in selector: & +selector.keys().size());
         //一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去
         i.remove();
         if(s.isAcceptable())
         {
           // 从channel()中取得我们刚刚注册的channel。
           Socket socket = ((ServerSocketChannel) s.channel()).accept();
           SocketChannel sc = socket.getChannel();
           sc.configureBlocking(false);
           sc.register(selector, SelectionKey.OP_READ SelectionKey.OP_WRITE);
                      System.out.println(++channels);
         }
         else
         {
           debug(&NBTest: Channel not acceptable&);
         }
      }
   else
      debug(&NBTest: Select finished without any keys.&);
private static void debug(String s)
  System.out.println(s);
private static void printKeyInfo(SelectionKey sk)
  String s = new String();
  s = &Att: & + (sk.attachment() == null ? &no& : &yes&);
  s += &, Read: & + sk.isReadable();
  s += &, Acpt: & + sk.isAcceptable();
  s += &, Cnct: & + sk.isConnectable();
  s += &, Wrt: & + sk.isWritable();
  s += &, Valid: & + sk.isValid();
  s += &, Ops: & + sk.interestOps();
  debug(s);
* @param args the command line arguments
public static void main (String args[])
  NBTest nbTest = new NBTest();
    nbTest.startServer();
    catch(Exception e)
    e.printStackTrace();
这是一段很常见的代码,注释已经写的很清楚,在此再总结一下。
首先,应用nio我们需要使用Selector,这是一个观察者模式的典型实现。我们的每个channel都必须注册到selector中才能被监听到。在sun.nio.ch.DefaultSelectorProvider(Selector的实现)内部有集合来存储我们的channel和对应的监听事件(已经封装为SelectionKey)。此时,我们的selector相当于观察者模式中的主题,一旦select方法被调用,就会遍历所有的观察者(此处是SelectionKey),调用它们统一的方法readyOps()来读取触发的事件,假设此处accept事件被触发,将会返回OP_ACCEPT(整型)。如果调用selector.selectedKeys(),将会以Set形式返回监听事件为OP_ACCEPT的所有SelectionKey,然后通过遍历集合,就可以找到我们的channel。java中提供的非阻塞类主要包含在java.nio,包括:
1、ServerSocketChannel:ServerSocket替代类,支持阻塞与非阻塞;
2、SocketChannel:Socket的替代类,支持阻塞与非阻塞;
3、Selector:为ServerSocketChannel监控接收连接就绪事件,为SocketChannel监控连接就绪、读和写事件;
4、SelctionKey:代表ServerSocketChannel及SocketChannel向Selector注册事件,当一个SelectionLKey对象位于Selector的selected-keys集合中时,就表示与这个SelectionKey相关的事件发生。
以上中,SocketChannel以及ServerSocketChannel均是SelectableChannel类的子类,而这个类又继承了Channel接口。
SelectableChannel类向Selector类注册来监控前者可能发生的事件,过程为:SelectionKey key = serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT)。
SocketChannel中发送和接收数据的方法为:
1、read(ByteBuffer buffer):将接收到的数据存放在指定的buffer中;
2、write(ButeBuffer buffer):将buffer中的数据发送出去。
Buffer(抽象类,位于java.nio包):
Buffer的属性:
1、容量,表示缓冲区可以保存的数据数量;
2、极限,表示换从去的当前终点,不能对超过缓冲区极限的区域进行读写,说白了就是极限之前的数据是有效的,之后的无效,不能大于容量;
3、位置,表示缓冲区下一个读写单元的位置,每次读写时会改变这个数值,不能大于极限;
缓冲区改变三个属性的方法:
1、clear(),极限设置为容量,位置置为0;
2、flip(),把极限设置为位置,再把位置置为0;
3、rewind(),不改变极限,把位置置为0。
Buffer有很多子类:
1、ByteBuffer,没有构造方法,需要静态类:
  1)、allocate(int capacity),返回ByteBuffer类对象,capacity指定缓冲区的大小;
  2)、directAllocate(int capacity),同上,I/O操作速度快,但是系统开销大。
2、除boolean之外的其它基本类型都有buffer类,都有allocate(int capacity)静态方法返回实例;
3、MappedByteBuffer,ButeBuffer类的子类,把缓冲区和文件某个区域直接映射。
读写缓冲区的方法如下:
1、get(),冲缓冲区当前位置读取一个单元数据,读完后把位置加1;
2、get(int index),绝对读,从index位置读数据但不改位置;
3、put(),向缓冲区当前位置写一个数据,然后位置加1;
4、put(int index),绝对写,向index位置写数剧单不改位置。
字符编码Charset(java.nio)
该类实例代表特定的字符编码类型,其编码与解码的方法如下:
1、ByteBuffer encode(String str),将字符串str转换为Byte并保存在ByteBuffer中;
2、ByteBuffer encode(CharBuffer cb),同上;
3、CharBuffer decode(ByteBuffer b),将b转换为CharBuffer;
Charset类中有静态方法forName(String encode)返回Charset对象,参数指定编码类型;还有一个defaultCharset()返回本平台默认字符编码的Charset对象。
Channel(java.nio.channels)接口用于连接缓冲区与数据源或者数据目的地,数据源的数据经过通道到达缓冲区,然后缓冲区的数据再经过通道到达目的地,其中包括两个方法:
1、close(),关闭通道;
2、isOpen(),判断通道是否打开。
Channel的子接口很多:
1、ReadableByeChannel接口,声明read(ByteBuffer dst),把数据源的数据读入到ByteBuffer;
2、WriteByteChannel接口,声明write(ByteBuffer src),将ByteBuffer中的数据写入到目的地。
3、ScatterByteChannel接口,分散读取数据,单个读取操作能填充多个缓冲区,它提供了read(ByteBuffer[] src),将读取的数据依次填充到ByteBuffer各个元素中;
4、GatheringByteChannel接口,集中写入数据,声明了write(ByteBuffer[] scrs),将各个ByteBuffer写入到指定的目的地;
5、FileChannel类,实现了ByteChannel、ScatteringByteChannel和GatherByteChannel,不能new,只能通过FileInputStream、FileOutputStrem、RandomAccessFile的getChannel()返回相应的FileChannel。
6、SelectableChannel,支持阻塞和非阻塞的I/O,其方法包括:
  1)、public SelectableChannel configureBlocking(boolean block) throws IOException,block为false时,表示为把SelectableChannel设置为非阻塞模式;
  2)、isBlocking()判断SelectableChannel是否为阻塞模式;
  3)、public SelectionKey register(Selector sel, int ops) throws ClosedChannelException;
  4)、public SelectionKey register(Selector sel,int ops,Object attachment) throws ClosedChannelException,这两个方法均向Selector注册事件,其中Object为SelectionKey关联的一个附件。
阅读(...) 评论()java NIO 实现非阻塞socket通信
java NIO 实现非阻塞socket通信
java的nio为非阻塞式socket通信提供了如下几个类:
& & & & & Selector : 它是SelectableChannel对象的多路复用器,所有希望采用非阻塞方式进行通信的channel都应该注册到Selector对象。可以通过调用此类的open()静态方法来创Selector实例,该方法将使用系统默认的Selector来返回新的Selector。 
Selector可以同时监控多个SelectortableChannel的IO状况,是非阻塞IO的核心。一个Selector实例有3个SelectIonKey集合
   1.所有的SelectionKey集合:代表了注册在该Selector上的Channel,该集合可以通过keys()方法返回。
   2.被选择的SelectionKey集合 : 代表了所有可通过select()方法获取的,需要进行IO处理的Channel,这个集合可以通过selectedKeys()返回。
   3.被取消的SelectionKey集合:代表了所有被取消注册关系的Channel,在下一次执行select()方法时,这些Channel对应的SelectionKey会被彻底删除,程序通常无须直接访问该集合。
Selector还提供了一系列和select()相关的方法。
& & & int select() : 监控所有注册的Channel,当它们中间有需要处理的IO操作时,该方法返回,并将对应的Selection加入被选择的SelectionKey集合中,该方法返回这些Channel的数量。
& & & int select(long timeout) : 可以设置超时时长的select()操作
& & & int selectNow() : 执行一个立即返回的select()操作,相对于无参数的select()方法而言,该方法不会阻塞线程。
& & & Selector wakeup() : 使一个还未返回的select()方法立刻返回
SelectableChannel类提供了如下方法来设置和返回该channel的模式状态
  SelectableChannel configureBlocking(boolean block) : 设置是否采用阻塞模式
  boolean isBlocking() : 返回该channel是否是阻塞模式
  int vaildOPs() : 返回一个整数值,表示这个Channel所支持的IO操作 OP_READ(1), OP_WRITE(4),OP_CONNECT(8),OP_ACCEPT(16)
SelectableChannel还提供了如下几个方法来获取它的注册状态
  boolean isRegistered() : 返回该channel是否注册在一个或多个selector上
  SelectionKey keyFor(Selector sel) : 返回该channel和sel Selector之间的注册关系,如果不存在注册关系,则返回null.
就像这个图,服务器上的所有channel都需要向Selector注册,Selector则负责监视这些socket的IO状态,当其中任意一个或者多个channel具有可用的IO操作,该Selector的select()方法将会返回大于0的整数,该整数表示该Selector上有多少个channel具有可用的IO操作,并提供了selectedKeys()方法来返回这些channel对应的SelectionKey集合。正是通过Selector,使得服务器端只需要不断的调用Selector实例的select()方法,即可知道当前的所有channel是否有需要处理的IO操作。当Selector上注册的所有channel都没有需要处理的IO操作时,select()方法将会被阻塞,调用该方法的线程被阻塞
服务器端的需要使用ServerSocketChannel来对客户端进行监听部分代码如下
如果需要使用非阻塞方式来处理该ServerSocketChannel,还应该设置它的非阻塞方式,并将其注册到指定的Selector,代码片段如下
我的热门文章
即使是一小步也想与你分享JAVA非阻塞通信(四)实验报告_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
JAVA非阻塞通信(四)实验报告
上传于|0|0|文档简介
&&JAVA非阻塞通信(四)实验报告
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩5页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢

我要回帖

更多关于 java 阻塞队列的实现 的文章

 

随机推荐