NIO:同步非阻塞IO

来源:BIO是同步阻塞IO操作,当线程在处理任务时,另一方会阻塞着等待该线程的执行完毕,为了提高效率,,JDK1.4后,引入NIO来提升数据的通讯性能

NIO中采用Reactor设计模式,注册的汇集点为Selector,NIO有三个主要组成部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器)

Reactor设计模式:Reactor模式是一种被动事件处理模式,即当某个特定事件发生时触发事件,可参考,https://blog.csdn.net/feimataxue/article/details/7642638https://www.cnblogs.com/bitkevin/p/5724410.html

NIO采用了轮询的方式来观察事件是否执行完毕,如:A让B打印某个文件,BIO会一直等待着B返回,期间自己不做其他事情,而NIO则会不断的询问B是否完成,未完成则处理自己的时,直至B完成

Channel(通道):Channel是一个对象,可以通过它读取和写入数据

Selector(对象选择器): Selector是一个对象,它可以注册到很多个Channel上,监听各个Channel上发生的事件,并且能够根据事件情况决定Channel读写

代码实现:(此实现参考网络上可用的例子)

NIO客户端实现:

package com.learn.nio.client;

import com.study.info.HostInfo;
import com.study.util.InputUtil; import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel; public class NIOEchoClient { public static void main(String[] args) throws Exception{
SocketChannel clientChannel = SocketChannel.open();
clientChannel.connect(new InetSocketAddress(HostInfo.HOST_NAME,HostInfo.PORT));
ByteBuffer buffer = ByteBuffer.allocate(50);
boolean flag = true;
while (flag){
buffer.clear();
String input = InputUtil.getString("请输入待发送的信息:").trim();
buffer.put(input.getBytes()); //将数据存入缓冲区
buffer.flip(); // 重置缓冲区
clientChannel.write(buffer); //发送数据
buffer.clear();
int read = clientChannel.read(buffer);
buffer.flip();
System.err.print(new String(buffer.array(), 0, read));
if("byebye".equalsIgnoreCase(input)){
flag = false;
}
}
clientChannel.close();
}
}

NIO服务端实现:

package com.learn.nio.server;

import com.study.info.HostInfo;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class NIOEchoServer { private static class EchoClientHandle implements Runnable { //客户端
private SocketChannel clientChannel;
// 循环结束标记
private boolean flag = true;
public EchoClientHandle(SocketChannel clientChannel){
this.clientChannel = clientChannel;
} @Override
public void run() {
ByteBuffer byteBuffer = ByteBuffer.allocate(50);
try {
while (this.flag){
byteBuffer.clear();
int read = this.clientChannel.read(byteBuffer);
String msg = new String(byteBuffer.array(), 0, read).trim();
String outMsg = "【Echo】" + msg + "\n"; // 回应信息
if("byebve".equals(msg)){
outMsg = "会话结束,下次再见!";
this.flag = false;
}
byteBuffer.clear();
byteBuffer.put(outMsg.getBytes()); //回传信息放入缓冲区
byteBuffer.flip();
this.clientChannel.write(byteBuffer);// 回传信息
}
}catch (Exception e){
e.printStackTrace();
}
}
} public static void main(String[] args) throws Exception{
// 为了性能问题及响应时间,设置固定大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
// NIO基于Channel控制,所以有Selector管理所有的Channel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
// 设置监听端口
serverSocketChannel.bind(new InetSocketAddress(HostInfo.PORT));
// 设置Selector管理所有Channel
Selector selector = Selector.open();
// 注册并设置连接时处理
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务启动成功,监听端口为:" + HostInfo.PORT);
// NIO使用轮询,当有请求连接时,则启动一个线程
int keySelect = 0;
while ((keySelect = selector.select()) > 0){
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey next = iterator.next();
if(next.isAcceptable()){ // 如果是连接的
SocketChannel accept = serverSocketChannel.accept();
if(accept != null){
executorService.submit(new EchoClientHandle(accept));
}
iterator.remove();
}
}
}
executorService.shutdown();
serverSocketChannel.close();
}
}

工具类:

package com.study.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class InputUtil {
private static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in)); private InputUtil(){
} public static String getString(String prompt){
boolean flag = true; //数据接受标记
String str = null;
while (flag){
System.out.println(prompt);
try {
str = KEYBOARD_INPUT.readLine(); // 读取一行数据
if(str == null || "".equals(str)){
System.out.println("数据输入错误,不允许为空!");
}else {
flag = false;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return str;
}
}
package com.study.info;

public calss HostInfo {
public static final String HOST_NAME = "localhost";
public static final int PORT = 9999;
}

NIO结构参考文章: https://www.cnblogs.com/sxkgeek/p/9488703.html#_label2

Java中NIO及基础实现的更多相关文章

  1. 第87节:Java中的Bootstrap基础与SQL入门

    第87节:Java中的Bootstrap基础与SQL入门 前言复习 什么是JQ? : write less do more 写更少的代码,做更多的事 找出所有兄弟: $("div" ...

  2. 第90节:Java中的Linux基础

    第90节:Java中的Linux基础 linux是装载虚拟机上面的: JDK依赖包: yum install glibc.i686 MYSQL依赖包: yum -y install libaio.so ...

  3. 并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础

    欢迎来到<并发王者课>,本文是该系列文章中的第14篇. 在黄金系列中,我们介绍了并发中一些问题,比如死锁.活锁.线程饥饿等问题.在并发编程中,这些问题无疑都是需要解决的.所以,在铂金系列文 ...

  4. java基础---->java中nio的使用(一)

    JDK 1.4 中引入的新输入输出 (NIO) 库在标准 Java 代码中提供了高速的.面向块的 I/O.今天我们就简单的学习一下nio的知识.我笑,便面如春花,定是能感动人的,任他是谁. nio的简 ...

  5. Java中的框架基础面试知识

    spring mvc 工作机制(原理): DispatcherServlet主要用作职责调度工作,本身主要用于控制流程 Spring mvc运行原理 1.springmvc将所有的请求都提交给Disp ...

  6. Java中NIO、BIO、AIO相关概念及应用场景

    1.同步阻塞IO(JAVA BIO):同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时,服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通 ...

  7. Java中NIO的简单介绍

    NIO基本介绍 Java NIO(New IO) 也有人称之为Java non-blocking IO 是从Java1.4版本开始引入的一个新的IO API,可以代替标准的IO API.NIO与原来的 ...

  8. 第86节:Java中的JQuery基础

    第86节:Java中的JQuery 前言复习 定时器: setInterval clearInterval setTimeout clearTimeout 显示: img.style.display ...

  9. java中的多线程 // 基础

    java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...

随机推荐

  1. 【Offer】[31] 【栈的压入、弹出序列】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如,序列{1,2,3 ...

  2. CentOS配置服务开机自启

    本例子以nginx作为举例: CentOS7中 以systemctl 替代了chkconfig 进行服务的管理, 默认在CentOS6 中控制服务开机自启,是在vim /etc/rc.d/rc.loc ...

  3. window下tomcat的下载安装和环境配置

    一.下载安装tomcat 去官网:http://tomcat.apache.org/  下载自己所需要的版本,解压在没有中文的文件夹路径下. 直接打开压缩包下面,进入bin目录,双击startup.b ...

  4. 'mvn' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    一定要发现自己的问题不要盲目从众 1.把maven的安装包解压 2.配置环境变量 3.配置path路径 4.在dos下测试一下 结果出现:'mvn' 不是内部或外部命令,也不是可运行的程序 或批处理文 ...

  5. Redis相关安装TCL

    安装相关命令 wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gzsudo tar -xzvf tcl8.6.1-src.tar. ...

  6. spring 事务配置方式以及事务的传播性、隔离级别

    在前面的文章中总结了spring事务的5中配置方式,但是很多方式都不用而且当时的配置使用的所有参数都是默认的参数,这篇文章就看常用的两种事务配置方式并信息配置事务的传播性.隔离级别.以及超时等问题,废 ...

  7. 编写自动匹配的下拉框(已解决IE8兼容)

    如何制作一个带匹配功能的下拉框? 之前看见layui有相关组件,但是发现,如果输入的内容在下拉框中没有相应的匹配,就会清空当前值,搞得我很不满意.有些代码是从网上扒下来的,但是找不到原地址了,凑合看吧 ...

  8. charles 结构体

    本文参考:charles 结构体 Charles 主要提供两种查看封包的视图,分别名为 Structure/结构视图 Sequence/序列视图 Structure/结构视图 将网络请求按访问的域名分 ...

  9. 04 (H5*) Vue第四天

    目录: 1:父组件向子组件传值,通过属性绑定的方式. 2:父组件向子组件传方法,通过事件绑定的方式 . 3:通过ref来获取Dom元素 1:父组件向子组件传值,通过属性绑定的方式 1.1:父组件声明数 ...

  10. C# 打印PPT幻灯片

    本文主要归纳总结了常见的几种PPT幻灯片文档打印的方法及需求.具体通过C#示例来分别阐述以下几种情况: 一.通过PresentationPrintDocument 对象来打印 使用默认打印机打印文档 ...