java核心技术-NIO

1、reactor(反应器)模式

  使用单线程模拟多线程,提高资源利用率和程序的效率,增加系统吞吐量。下面例子比较形象的说明了什么是反应器模式:

  一个老板经营一个饭店,

  传统模式 - 来一个客人安排一个服务员招呼,客人很满意;(相当于一个连接一个线程)

  后来客人越来越多,需要的服务员越来越多,资源条件不足以再请更多的服务员了,传统模式已经不能满足需求。老板之所以为老板自然有过人之处,老板发现,服务员在为客人服务时,当客人点菜的时候,服务员基本处于等待状态,(阻塞线程,不做事)。

  于是乎就让服务员在客人点菜的时候,去为其他客人服务,当客人菜点好后再招呼服务员即可。 --反应器(reactor)模式诞生了

  饭店的生意红红火火,几个服务员就足以支撑大量的客流量,老板用有限的资源赚了更多的money~~~~^_^

 通道:类似于流,但是可以异步读写数据(流只能同步读写),通道是双向的,(流是单向的),通道的数据总是要先读到一个buffer 或者 从一个buffer写入,即通道与buffer进行数据交互。

  

通道类型:  

FileChannel:从文件中读写数据。  
DatagramChannel:能通过UDP读写网络中的数据。  
SocketChannel:能通过TCP读写网络中的数据。  
ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。  
 - FileChannel比较特殊,它可以与通道进行数据交互, 不能切换到非阻塞模式,套接字通道可以切换到非阻塞模式;

缓冲区 - 本质上是一块可以存储数据的内存,被封装成了buffer对象而已!

  

缓冲区类型:

ByteBuffer  
MappedByteBuffer  
CharBuffer  
DoubleBuffer  
FloatBuffer  
IntBuffer  
LongBuffer  
ShortBuffer  
常用方法:

allocate() - 分配一块缓冲区  
put() - 向缓冲区写数据
get() - 向缓冲区读数据  
filp() - 将缓冲区从写模式切换到读模式  
clear() - 从读模式切换到写模式,不会清空数据,但后续写数据会覆盖原来的数据,即使有部分数据没有读,也会被遗忘;  
compact() - 从读数据切换到写模式,数据不会被清空,会将所有未读的数据copy到缓冲区头部,后续写数据不会覆盖,而是在这些数据之后写数据
mark() - 对position做出标记,配合reset使用
reset() - 将position置为标记值    
缓冲区的一些属性:

capacity - 缓冲区大小,无论是读模式还是写模式,此属性值不会变;
position - 写数据时,position表示当前写的位置,每写一个数据,会向下移动一个数据单元,初始为0;最大为capacity - 1,切换到读模式时,position会被置为0,表示当前读的位置

limit - 写模式下,limit 相当于capacity 表示最多可以写多少数据,切换到读模式时,limit 等于原先的position,表示最多可以读多少数据。

非直接缓冲区:通过allocate() 方法 分配缓冲区,将缓冲区建立在JVM内存中

直接缓冲区:通过allocateDirect() 方法直接缓冲区 将缓冲区建立在物理内存中

2.1 关于缓冲区各个属性的测试

    String str = "abcde";//1. 分配一个指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);System.out.println("--------------allocate()----------------");System.out.println(buf.position());//0System.out.println(buf.limit());//1024System.out.println(buf.capacity());//1024//2. 利用put存入数据到缓冲区中去buf.put(str.getBytes());System.out.println("----------------put()-------------------");System.out.println(buf.position());//5System.out.println(buf.limit());//1024System.out.println(buf.capacity());//1024//3. 切换到读取模式buf.flip();System.out.println("----------------flip()------------------");System.out.println(buf.position());//0System.out.println(buf.limit());//5System.out.println(buf.capacity());//1024//4. 利用get() 读取缓冲区中的数据byte[] dst = new byte[buf.limit()];buf.get(dst);System.out.println(new String(dst,0,dst.length));System.out.println("----------------get()------------------");System.out.println(buf.position());//5System.out.println(buf.limit());//5System.out.println(buf.capacity());//1024//5.可重复读buf.rewind();System.out.println("----------------rewind()------------------");System.out.println(buf.position());//0System.out.println(buf.limit());//5System.out.println(buf.capacity());//1024//6.clear(): 清空缓冲区, 但是缓冲区的数据依然存在, 但是处于被遗忘的状态buf.clear();System.out.println("----------------clear()-------------------");System.out.println(buf.position());//0System.out.println(buf.limit());//1024System.out.println(buf.capacity());//1024byte[] newByte = new byte[buf.limit()];buf.get(newByte);System.out.println(new String(newByte,0,newByte.length));

2.2 关于通道的使用

1.利用通道进行 文件的复制 非直接缓冲区

    FileInputStream fis = null;FileOutputStream fos = null;FileChannel inChannel = null;FileChannel outChannel = null;try {fis = new FileInputStream("1.jpg");fos = new FileOutputStream("2.jpg");// ①获取通道inChannel = fis.getChannel();outChannel = fos.getChannel();// ②将通道中的数据存入缓冲区ByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 将通道中的数据存入缓冲区while (inChannel.read(byteBuffer) != -1) {byteBuffer.flip(); // 切换读取数据的模式outChannel.write(byteBuffer);byteBuffer.clear();}} catch (IOException e) {e.printStackTrace();} finally {if (inChannel != null) {try {inChannel.close();} catch (IOException e) {e.printStackTrace();}}if (outChannel != null) {try {outChannel.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}

2.通道之间的传输

CREATE_NEW:如果文件不存在就创建,存在就报错

CREATE:如果文件不存在就创建,存在创建(覆盖)

    FileChannel inChannel = null;FileChannel outChannel = null;try {inChannel = FileChannel.open(Paths.get("hello.txt"), StandardOpenOption.READ);outChannel = FileChannel.open(Paths.get("hello2.txt"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW);inChannel.transferTo(0, inChannel.size(), outChannel);} catch (Exception e) {e.printStackTrace();}  finally {if(inChannel != null){try {inChannel.close();} catch (IOException e) {e.printStackTrace();}}if(outChannel != null){try {outChannel.close();} catch (IOException e) {e.printStackTrace();}}}
  1. 使用直接缓冲区完成内存文件的复制

    FileChannel inChannel = null;
    FileChannel outChannel = null;
    try {inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);outChannel = FileChannel.open(Paths.get("x.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW);MappedByteBuffer inMappedBuffer = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());MappedByteBuffer outMappedBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());System.out.println(inMappedBuffer.limit());byte[] b = new byte[inMappedBuffer.limit()];;inMappedBuffer.get(b);outMappedBuffer.put(b);} catch (Exception e) {e.printStackTrace();
    } finally {if(inChannel != null){try {inChannel.close();} catch (IOException e) {e.printStackTrace();}}if(outChannel != null){try {outChannel.close();} catch (IOException e) {e.printStackTrace();}}}

    2.3 重点 NIO-非阻塞IO

个人认为 NIO 最难的两点 一个是对于选择器和选择键的理解 其次是对于网络通信模型的理解

本章内容以防过长 只讲解 NIO 的使用方法 上述两点参看下回分解

阻塞IO示例:

//客户端
@Test
public void client() throws IOException{SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);ByteBuffer buf = ByteBuffer.allocate(1024);while(inChannel.read(buf) != -1){buf.flip();sChannel.write(buf);buf.clear();}sChannel.shutdownOutput();//接收服务端的反馈int len = 0;while((len = sChannel.read(buf)) != -1){buf.flip();System.out.println(new String(buf.array(), 0, len));buf.clear();}inChannel.close();sChannel.close();
}//服务端
@Test
public void server() throws IOException{ServerSocketChannel ssChannel = ServerSocketChannel.open();FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);ssChannel.bind(new InetSocketAddress(9898));SocketChannel sChannel = ssChannel.accept();ByteBuffer buf = ByteBuffer.allocate(1024);while(sChannel.read(buf) != -1){buf.flip();outChannel.write(buf);buf.clear();}//发送反馈给客户端buf.put("服务端接收数据成功".getBytes());buf.flip();sChannel.write(buf);sChannel.close();outChannel.close();ssChannel.close();
}

非阻塞IO示例-TCP:

//客户端br/>@Test
public void client() throws IOException{
//1. 获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));

    //2. 切换非阻塞模式sChannel.configureBlocking(false);//3. 分配指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);//4. 发送数据给服务端Scanner scan = new Scanner(System.in);while(scan.hasNext()){String str = scan.next();buf.put((new Date().toString() + "\n" + str).getBytes());buf.flip();sChannel.write(buf);buf.clear();}//5. 关闭通道sChannel.close();
}//服务端
@Test
public void server() throws IOException{//1. 获取通道ServerSocketChannel ssChannel = ServerSocketChannel.open();//2. 切换非阻塞模式ssChannel.configureBlocking(false);//3. 绑定连接ssChannel.bind(new InetSocketAddress(9898));//4. 获取选择器Selector selector = Selector.open();//5. 将通道注册到选择器上, 并且指定“监听接收事件”ssChannel.register(selector, SelectionKey.OP_ACCEPT);//6. 轮询式的获取选择器上已经“准备就绪”的事件while(selector.select() > 0){//7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”Iterator<SelectionKey> it = selector.selectedKeys().iterator();while(it.hasNext()){//8. 获取准备“就绪”的是事件SelectionKey sk = it.next();//9. 判断具体是什么事件准备就绪if(sk.isAcceptable()){//10. 若“接收就绪”,获取客户端连接SocketChannel sChannel = ssChannel.accept();//11. 切换非阻塞模式sChannel.configureBlocking(false);//12. 将该通道注册到选择器上sChannel.register(selector, SelectionKey.OP_READ);}else if(sk.isReadable()){//13. 获取当前选择器上“读就绪”状态的通道SocketChannel sChannel = (SocketChannel) sk.channel();//14. 读取数据ByteBuffer buf = ByteBuffer.allocate(1024);int len = 0;while((len = sChannel.read(buf)) > 0 ){buf.flip();System.out.println(new String(buf.array(), 0, len));buf.clear();}}//15. 取消选择键 SelectionKeyit.remove();}}
}

非阻塞IO示例-UDP:

@Test
public void send() throws IOException{DatagramChannel dc = DatagramChannel.open();dc.configureBlocking(false);ByteBuffer buf = ByteBuffer.allocate(1024);Scanner scan = new Scanner(System.in);while(scan.hasNext()){String str = scan.next();buf.put((new Date().toString() + ":\n" + str).getBytes());buf.flip();dc.send(buf, new InetSocketAddress("127.0.0.1", 9898));buf.clear();}dc.close();
}@Test
public void receive() throws IOException{DatagramChannel dc = DatagramChannel.open();dc.configureBlocking(false);dc.bind(new InetSocketAddress(9898));Selector selector = Selector.open();dc.register(selector, SelectionKey.OP_READ);while(selector.select() > 0){Iterator<SelectionKey> it = selector.selectedKeys().iterator();while(it.hasNext()){SelectionKey sk = it.next();if(sk.isReadable()){ByteBuffer buf = ByteBuffer.allocate(1024);dc.receive(buf);buf.flip();System.out.println(new String(buf.array(), 0, buf.limit()));buf.clear();}}it.rem    欢迎工作一到五年的Java工程师朋友们加入Java群: 891219277

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

转载于:https://blog.51cto.com/14084556/2324364

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/389048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物种分布模型_减少物种分布建模中的空间自相关

物种分布模型Species distribution models (SDM; for review and definition see, e.g., Peterson et al., 2011) are a dominant paradigm to quantify the relationship between environmental dynamics and several manifestations of species biogeography. These statisti…

BZOJ1014: [JSOI2008]火星人prefix

BZOJ1014: [JSOI2008]火星人prefix Description 火星人最近研究了一种操作&#xff1a;求一个字串两个后缀的公共前缀。 比方说&#xff0c;有这样一个字符串&#xff1a;madamimadam&#xff0c;我们将这个字符串的各个字符予以标号&#xff1a; 序号&#xff1a; 1 2 3 4 5 6…

redis将散裂中某个值自增_这些Redis命令你都掌握了没?

本章主要内容字符串命令、列表命令和集合命令散列命令和有序集合命令发布命令与订阅命令其他命令本章将介绍一些没有在第1章和第2章出现过的Redis命令&#xff0c;学习这些命令有助于读者在已有示例的基础上构建更为复杂的程序&#xff0c;并学会如何更好地去解决自己遇到的问题…

asp.net的MessageBox

public class MessageBox{ public enum MsgButton { /// <summary> /// 只是OK按钮 /// </summary> OK 1, /// <summary> /// 提示是否确定 /// </summary> OKCancel 2 } publ…

深入理解激活函数

为什么需要非线性激活函数&#xff1f; 说起神经网络肯定会降到神经函数&#xff0c;看了很多资料&#xff0c;也许你对激活函数这个名词会感觉很困惑&#xff0c; 它为什么叫激活函数&#xff1f;它有什么作用呢&#xff1f; 看了很多书籍上的讲解说会让神经网络变成很丰富的…

如何一键部署项目、代码自动更新

为什么80%的码农都做不了架构师&#xff1f;>>> 摘要&#xff1a;my-deploy:由nodejs写的一个自动更新工具,理论支持所有语言(php、java、c#)的项目,支持所有git仓库(bitbucket、github等)。github效果如何?如果你的后端项目放在github、bitbucket等git仓库中管理…

Kettle7.1在window启动报错

实验环境&#xff1a; window10 x64 kettle7.1 pdi-ce-7.1.0.0-12.zip 错误现象&#xff1a; a java exception has occurred 问题解决&#xff1a; 运行调试工具 data-integration\SpoonDebug.bat //调试错误的&#xff0c;根据错误明确知道为何启动不了&#xff0c;Y--Y-…

opa847方波放大电路_电子管放大电路当中阴极电阻的作用和选择

胆机制作知识视频&#xff1a;6P14单端胆机用示波器方波测试输出波形详细步骤演示完整版自制胆机试听视频&#xff1a;胆机播放《猛士的士高》经典舞曲 熟悉的旋律震撼的效果首先看下面这一张300B电子管电路图&#xff1a;300B单端胆机原理图图纸里面画圆圈的电阻就是放大电路当…

键盘钩子

C#键盘钩子//*************************键盘钩子********************** //定义变量 public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); static int hKeyboardHook 0; HookProc KeyboardHookProcedure; /************************* * 声明API函数 * ***…

matplotlib基础函数函数 plot, figure

matplotlib.pyplot.plot(*args, scalexTrue, scaleyTrue,dataNone,**kwargs) 用线段和标记去绘制x和y。调用签名&#xff1a; plot([x], y, [fmt], *, dataNone, **kwargs) plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)点或线的坐标由x, y给出 操作参数 fmt 是为了…

清洁数据ploy n_清洁屋数据

清洁数据ploy nAs a bootcamp project, I was asked to analyze data about the sale prices of houses in King County, Washington, in 2014 and 2015. The dataset is well known to students of data science because it lends itself to linear regression modeling. You …

redis安装redis集群

NoSql数据库之Redis1、什么是nosql&#xff0c;nosql的应用场景2、Nonsql数据库的类型a) Key-valueb) 文档型&#xff08;类似于json&#xff09;c) 列式存储d) 图式3、redis的相关概念kv型的。4、Redis的安装及部署5、Redis的使用方法及数据类型a) Redis启动及关闭b) Redis的数…

联想拯救者y7000p加内存条_内存、硬盘不够用?手把手教你升级联想拯救者Y7000P...

由于这两年内存价格的高企&#xff0c;主流笔记本的内存容量被锁定在 8GB 已经有了相当长的时间。作为近几个月最热门的游戏本产品&#xff0c;联想拯救者 Y7000P 除顶配之外同样使用的是 8GB 内存和 512GB 固态硬盘的配置。所以买到这款机器的玩家多数都会选择进行内存和硬盘的…

机器学习实践一 logistic regression regularize

Logistic regression 数据内容&#xff1a; 两个参数 x1 x2 y值 0 或 1 Potting def read_file(file):data pd.read_csv(file, names[exam1, exam2, admitted])data np.array(data)return datadef plot_data(X, y):plt.figure(figsize(6, 4), dpi150)X1 X[y 1, :]X2 X[…

ajax+webservice

版本为AJAX November CTP 三个示例分别为&#xff1a;1 带参数的WS方法2 不带参数的WS方法3 参数类型为DataTable的WS方法 一、WebMethod注意要点&#xff1a;1 WebMethod类需要添加命名空间 Microsoft.Web.Script.Services&#xff0c;此空间需要引用Microsoft.Web.Preview.dl…

深度学习数据扩张_适用于少量数据的深度学习结构

作者&#xff1a;Gorkem Polat编译&#xff1a;ronghuaiyang导读一些最常用的few shot learning的方案介绍及对比。传统的CNNs (AlexNet, VGG, GoogLeNet, ResNet, DenseNet…)在数据集中每个类样本数量较多的情况下表现良好。不幸的是&#xff0c;当你拥有一个小数据集时&…

时间管理

时间管理 时间管理是运用策略和技术&#xff0c;帮助你尽可能有效地利用你的时间。 不仅仅是要将时间用在正确的地方&#xff0c; 而且还要将尽可能有效地加以利用。 目前是如何利用时间的&#xff1a; 意识是时间管理的先决条件。目标提供路线图。选择是难点。 意识 第一条…

基于边缘计算的实时绩效_基于绩效的营销中的三大错误

基于边缘计算的实时绩效We’ve gone through 20% of the 21st century. It’s safe to say digitalization isn’t a new concept anymore. Things are fully or at least mostly online, and they tend to escalate in the digital direction. That’s why it’s important to…

本线程钩子

钩子其实就是调用一下API而已&#xff1a; 1、安装钩子&#xff1a;   SetWindowsHookEx 函数原形&#xff1a;HHOOK SetWindowsHookEx( int idHook, // 钩子类型&#xff0c; HOOKPROC lpfn, // 钩子函数地址…

Maven Web项目解决跨域问题

跨域问题目前笔者所用到的方案大致有三种:jsonp,SpringMVC 4以上注解方式和cros三方过滤器。 Jsonp JSONP(JSON with Padding)是一个非官方的协议&#xff0c;它允许在服务器端集成Script tags返回至客户端&#xff0c;通过javascript callback的形式实现跨域访问&#xff08;这…