lecture4非阻塞通信

上传人:飞*** 文档编号:54588437 上传时间:2018-09-15 格式:PPT 页数:91 大小:269KB
返回 下载 相关 举报
lecture4非阻塞通信_第1页
第1页 / 共91页
lecture4非阻塞通信_第2页
第2页 / 共91页
lecture4非阻塞通信_第3页
第3页 / 共91页
lecture4非阻塞通信_第4页
第4页 / 共91页
lecture4非阻塞通信_第5页
第5页 / 共91页
点击查看更多>>
资源描述

《lecture4非阻塞通信》由会员分享,可在线阅读,更多相关《lecture4非阻塞通信(91页珍藏版)》请在金锄头文库上搜索。

1、第四章 非阻塞通信,主要内容,线程阻塞的概念 Java.nio包中类的介绍: ServerSocketChannel SocketChannel Selector/SelectionKey/ByteBuffer等 阻塞模式与非阻塞模式的实现,4.1线程阻塞的概念,处于阻塞状态的线程共同特征: 1、放弃CPU,暂停运行,只有等待导致阻塞的原因消除,才能恢复运行; 2、或者被其他线程中断,该线程会退出阻塞状态,并且抛出InterruptedException,4.1线程阻塞的原因,1、线程执行Thread.sleep(int n); 2、线程要执行一段同步代码 3、线程执行了一个对象的wait()

2、方法,只有其他线程执行了该对象的notify()或notifyAll()方法,才能将其唤醒 4、线程执行I/O操作,如ReadLine之类的方法。,客户程序线程进入阻塞状态的情况,1、客户程序与服务器建立连接时,会进入阻塞状态,直到连接成功,线程才返回 2、线程从Socket的输入流读入数据时,如果没有足够的数据,就进入阻塞状态,直到读到足够数据,或到达输入流末尾,或者异常,才会返回。输入流的不同读方法: int read():输入一个字节就足够 int read(byte buff):输入流字节数和数组长度相同 String readLine():输入流中有一行字符串就足够,需要Buffer

3、Reader的此方法。,客户程序线程进入阻塞状态的情况,3、线程从Socket的输出流写数据时,可能进入阻塞状态,等待输出了所有数据或者出现异常,才从输出流的write()方法返回或者异常中断 4、调用Socket的close()方法时如果设置了关闭Socket的延迟时间,会进入阻塞,直到底层 Socket发完所有数据,或者超过setSoLinger()方法设置的延迟时间,才从close()方法返回。,服务器程线程进入阻塞状态的情况,1、线程执行ServerSocket的accept()方法 2、线程从Socket的输入流读入数据,同客户端 3、线程从Socket的输出流写出数据,同客户端综上

4、,通过Socket的输入输出流来读写数据时,都可能进入阻塞状态。这种可能出现阻塞的输入输出操作称为阻塞I/O 与此对照,如果这种输入输出流读写操作不发生阻塞,则称为非阻塞I/O,4.1.2服务器多线程处理阻塞通信局限,创建ServerSocket,接收连接accept,委派任务给工作线程,等待任务,接收请求数据,发送响应数据,关闭连接,通信结束?,否,主线程,工作线程,红色标志步骤为可能阻塞,一旦阻塞,需要转让线程CPU使用权,4.1.2服务器多线程处理阻塞通信局限,局限: 每个线程分配独立的堆栈空间,线程调度、同步、死锁可能 很多时间浪费在阻塞IO操作上,线程切换频繁,非阻塞通信的基本思想,

5、一心多用 轮询while 处理流程 While(一直等待,直到有接收连接就绪事件、读就绪事件、写就绪事件发生)/阻塞 If(有客户连接)接收客户连接;/非阻塞 If(Socket输入流有可读数据)从输入流中读数据; /非阻塞 If(Socket输出流可写数据)向输出流中写数据; /非阻塞,Java.nio包中的主要类,以下支持阻塞和非阻塞通信的类 ServerSocketChannel:ServerSocket的替代类,支持阻塞与非阻塞通信SocketChannel:Socket的替代类,同上Selector:为ServerSocketChannel监控接收连接就绪事件,为SocketChan

6、nel监控连接就绪、读就绪、写就绪事件。,Java.nio包中的主要类,SelectionKey:代表ServerSocketChannel 和SocketChannel向Selector注册事件的句柄,当一个SelectionKey对象位于Selector对象的selected-keys集合中时,就表示与这个SelectionKey对象相关的事件发生了。,Java.nio包中的主要类,如何注册事件的呢? ServerSocketChannel向Selector注册接收连接就绪事件的代码如下:注册事件过程 SelectionKey key = serverSocketChannel.regis

7、ter(selector, SelectionKey.OP_ACCEPT);,Java.nio包中的主要类,interface Channel,interface ByteChannel,SelectableChannel,ServerSocketChannel,SocketChannel,ServerSocketChannel和SocketChannel都是SelectableChannel的子类, SelectableChannel及其子类都能委托Selector来监控它们可能发生的一些事件,这个委托过程也称为注册事件过程,SelectionKey类静态常量事件类型,SelectionKe

8、y的一些静态常量表示事件类型 ServerSocketChannel只可能发生一种事件: SelectionKey.OP_ACCEPT:接收就绪事件,表示至少有一个客户连接,服务器可以接收连接。,SelectionKey类静态常量事件类型,SocketChannel可能发生三种事件:SelectionKey.OP_CONNECT:连接就绪事件,表示客户与服务器的连接已经成功建立了。 SelectionKey.OP_READ:读就绪事件,输入流中已有可读数据,可以执行读操作了 SelectionKey.OP_WRITE:写就绪事件,可以向输出流写数据了。,SocketChannel的接收和发送数

9、据方法,read(ByteBuffer buffer):接收数据,并将数据存到参数指定的ByteBuffer中。 write(ByteBuffer buffer):将参数指定的buffer中的数据发送出去。ByteBuffer表示字节缓冲区,两个方法都会操作它。继承于Buffer类。是特定的基本类型元素的线性、有限序列 ByteBuffer中存放的是字节,为转换为字符串,还需要用到Charset类,表示字符编码,提供了从字节流转换为字符串和字符串转换为字节流的方法。,缓冲区Buffer,数据输入输出往往是比较耗时的操作。缓冲区可以从两个方面提高IO操作的效率 减少实际的物理读写次数。 缓冲区在

10、创建时被分配内存,这块内存一直被重用,减少动态分配和回收的次数。 缓冲区属性: 容量(capacity)、限制(limit)、位置(position).对应的方法:clear()、flip()、rewind(),缓冲区Buffer,容量(capacity):表示缓冲区可以保存多少数据 限制(limit):表示缓冲区的当前终点,不能对缓冲区中超过极限的区域进行读写操作,是不应读取或写入的第一个元素的索引 位置(position):是下一个要读取或写入的元素的索引,改变属性,clear()方法:清除此缓冲区。将位置设置为零,限制设置为该容量,并且丢弃标记。 在使用序列信道读取或 put 操作填充此

11、缓冲区之前调用此方法。例如: buf.clear(); / Prepare buffer for reading in.read(buf); / Read data 此方法不能实际擦除缓冲区中的数据,但从名称来看似乎能够擦除,因为它多数情况下确实是在擦除数据时使用的,改变属性,filp()方法:反转此缓冲区。首先对当前位置设置限制,然后将该位置设置为零。如果已定义了标记,则丢弃该标记。 在序列信道读取或 put 操作之后,调用此方法以做好序列信道写入或相对 get 操作。例如: buf.put(magic); / Prepend header in.read(buf); / Read data

12、 into rest of buffer buf.flip(); / Flip buffer out.write(buf); / Write header + data to channel,改变属性,rewind()方法:使缓冲区做好了重新读取已包含的数据的准备:它使限制保持不变,并将位置设置为零 。 重绕此缓冲区。将位置设置为零并丢弃标记。 在序列信道写入或 get 操作之前调用此方法(假定已经适当设置了限制)。例如: out.write(buf); / Write remaining databuf.rewind(); / Rewind buffer buf.get(array); /

13、Copy data into array,Bufferdemo,import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel;,Bufferdemo,public class BufferDemo public static void main(String args) throws Exception. /分配一个非直接缓冲区 ByteBuffer bb = ByteBuffer.allocate

14、(100); /向缓冲区写入0到100的字节制 for(int i = 0; i 100; i+). byte b = (byte) (Math.random() * 100); bb.put(b); System.out.println(“写入文件前的缓冲区数据“); bb.flip(); while(bb.hasRemaining() System.out.print(bb.get() + “ “); System.out.println(“读取缓冲区数据完毕”);,Bufferdemo,/获取一个关联到文件buffer.txt的信道 FileChannel fc = new FileOu

15、tputStream(“buffer.txt“).getChannel(); /将缓冲区数据写到文件中 bb.flip(); fc.write(bb); /防止缓存 fc.force(true); /关闭信道 fc.close(); bb = null; fc = null;,Bufferdemo,/下面从文件中读取数据 fc = new FileInputStream(“buffer.txt“).getChannel(); ByteBuffer bb2 = ByteBuffer.allocate(int) fc.size(); fc.read(bb2); System.out.println

16、(“从文件读取的缓冲区数据“); bb2.flip(); while(bb2.hasRemaining() System.out.print(bb2.get() + “ “); System.out.println(); fc.close(); bb2 = null; fc = null; ,缓冲区Buffer的创建方法,Buffer类是一个抽象类,共有8个具体缓冲类,其中最基本的缓冲区是ByteBuffer,它存放的数据单元是字节。 ByteBuffer类并没有提供公开的构造方法,但是提供了两个获得ByteBuffer实例的静态工厂方法 allocate(int capacity):返回一个容量大小为capacity的缓冲区 directAllocate(int capacity):返回一个容量大小为capacity的直接缓冲区,开销相对大,只有当缓冲区较大并长期存在,或经常需要重用,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号