2.1 传统的BIO编程

  以服务器为例,在传统BIO模型下的服务器,每当一个新的请求到来的时候回分配一个线程去处理该请求,并且该线程在执行IO操作的时候会一直阻塞,知道IO操作完成或抛出异常才会返回。当网络情况不佳时,网络IO可能会耗费大量时间,那么就会同时有大量线程在服务器上阻塞着,很容易造成内存溢出。

  这种模型被称为同步阻塞模型,同步指的是只有等待线程IO操作完成该线程才会返回,阻塞指的是IO没有完成的时候一直等待。

  

2.1.1 服务端代码

  Server类,监听8080端口,在while循环里Server端阻塞在server.accept上,即等待请求传到8080端口上,从accept方法返回。后续new Thread是新建一个线程去处理请求。

public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080;
ServerSocket server = null; try {
server = new ServerSocket(port);
System.out.println("The server start in port "+port);
Socket socket = null;
while (true){
socket = server.accept();
Thread thread = new Thread(new TimeServerHandler(socket));
thread.start();
} } catch (IOException e) {
e.printStackTrace();
} finally {
if (server!=null){
System.out.println("Time server close");
server.close();
server=null;
}
}
}
}

  执行代码用jstack打印线程状态,看到server线程在17行“停止”,即阻塞在17行等待请求传过来。这种阻塞就是BIO里的B,block,一个IO没有完成就一直卡在那里。

  有新的客户端接入新建线程执行处理方法,通过检查传过来的字符串是否是要求的“QUERY TIME ORDER”,如果是就返回当前服务器的时间,否则返回错误信息。

public class TimeServerHandler implements Runnable {
private Socket socket; public TimeServerHandler(Socket socket) {
this.socket = socket;
} public void run() {
BufferedReader in = null;
PrintWriter out = null; try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(),true);
String currentTime = null;
String body = null;
while (true){
body = in.readLine();
if (body == null){
break;
}
System.out.println("The time server receive order: "+body);
currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new Date(System.currentTimeMillis()).toString():"BAD ORDER";
out.println(currentTime);
}
} catch (IOException e) {
e.printStackTrace();
if (in!=null){
try {
in.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (out!=null){
out.close();
out = null;
} if (socket!=null){
try {
socket.close();
} catch (IOException ex) {
ex.printStackTrace();
}finally {
socket=null;
}
}
}
}
}

  同时开启服务端和客户端后可以在控制台看到输出。

2.1.2 缺点

  • 每个请求都需要一个新建线程去处理,扛不住太大的并发,因为没有给线程数目设置瓶颈。
  • BIO会在网络不佳情况导致大量线程。

2.2 伪异步IO编程

2.2.1 代码

  用线程池代替不停的新建线程,好处是线程池是有界的,避免在极端情况下不停新建线程。

public class TimeServer_ThreadPool {
public static void main(String[] args) {
int port = 8080;
ServerSocket server = null;
try {
server = new ServerSocket(port);
System.out.println("server start at port "+ port);
Socket socket = null;
ExecutorService pool = Executors.newFixedThreadPool(10);
while (true){
socket = server.accept();
pool.execute(new TimeServerHandler(socket));
} } catch (IOException e) {
e.printStackTrace();
}
}
}

2.2.2 弊端

  • 使用BIO读取数据时,线程会一直阻塞直到 1、有数据读 2、数据读取完毕 3、抛出异常。当客户端请求发送较慢或者网络时延较时,读取数据的线程会一直阻塞。
  • 使用BIO输出数据时,线程会一直阻塞直到  1、有数据写 2、数据写完 3、抛出异常。当服务端写数据时,如果网络情况不佳,客户端不能及时读取数据,大量数据留在TCP缓冲区,当发送端即服务端的Window size为0的时候写线程就会无法继续写从而阻塞。
  • 无论读还是写,都是阻塞的,阻塞与否以及阻塞是否严重依赖于网络传输的质量。
  • 当线程池的队列使用阻塞队列时,前台线程负责把请求封装成对象加入线程池的阻塞队列,如果网络状况十分的差,阻塞队列也满了,那么复制把请求对象加入阻塞队列的前台线程也会阻塞,整个系统失去异步性,所有的请求都会超时。

  

2.3 NIO 编程

  NIO与BIO的区别在两点

  • 面向的对象不同。BIO面向Stream,该Stream是单向通信,只能是读Stream或者写Stream。NIO面向Buffer,NIO面向buffer和channel,channel是铁路,buffer是铁路上运输的数据。
  • 阻塞性。BIO是阻塞的,NIO通过Selector实现多路复用。

2.3.1 Buffer与Channel

  

第2章 NIO入门的更多相关文章

  1. 第二章 NIO入门

    传统的同步阻塞式I/O编程 基于NIO的非阻塞编程 基于NIO2.0的异步非阻塞(AIO)编程 为什么要使用NIO编程 为什么选择Netty 第二章 NIO 入门 2.1 传统的BIO编程 2.1.1 ...

  2. (基础篇 走进javaNIO)第二章-NIO入门

    在本章巾,我们会分别对 JDK 的BIO ,NIO 和JDK 1.7 最新提供的 NI02.0的使用进行详细说明 ,通过流程图和代 码讲解,让大 家体会到随着 Ja va 1/0 类库的 不断发展和改 ...

  3. 第1章Java入门体验

    第1章Java入门体验 1.java简介和平台应用 Java是sun公司开发出来,现在属于ORACLE公司java分为几个部分:首先是最基础的Java SE部分,这部分是Java的基础知识,主要包括: ...

  4. 第三章 Docker 入门

    第三章 docker 入门 3.1 确保docker已经就绪 首先查看docker程序是否存在,功能是否正常 [#3#cloudsoar@cloudsoar-virtual-machine ~]$su ...

  5. Java NIO入门(二):缓冲区内部细节

    Java NIO 入门(二)缓冲区内部细节 概述 本文将介绍 NIO 中两个重要的缓冲区组件:状态变量和访问方法 (accessor). 状态变量是前一文中提到的"内部统计机制"的 ...

  6. Java NIO入门

    NIO入门 前段时间在公司里处理一些大的数据,并对其进行分词.提取关键字等.虽说任务基本完成了(效果也不是特别好),对于Java还没入门的我来说前前后后花了2周的时间,我自己也是醉了.当然也有涉及到机 ...

  7. 第二章 MySQL入门篇

    第一章 MySQL入门篇 一.MySql简介 简言: 和SQL Server数据库相同,MySQl也是一个关系型数据库管理系统.由瑞典的MySQL AB公司开发,2008年被SUN公司收购,2009年 ...

  8. Kettle解决方案: 第一章ETL入门

    第一章ETL入门 1.1 OLPT和数据仓库对比 普通的事务系统和商业智能系统(BI)有什么区别? 1个独立的普通事务系统也被称为在线事务处理系统(OLTP) 商业智能系统也常被称为决策支持系统(DS ...

  9. 学习Zookeeper之第1章Zookeeper入门

    第 1 章 Zookeeper入门 1.1 概述 1.2 特点 1.3 数据结构 1.4 应用场景 统一命名服务 统一配置管理 统一集群管理 服务器动态上下线 软负载均衡 1.5 下载地址 第 1 章 ...

随机推荐

  1. 实现一个自己的IOC

    实现一个自己的IOC package com.IocExample; import java.lang.reflect.Constructor; import java.lang.reflect.In ...

  2. Linux 服务器远程管理

    一.Linux 常用远程管理工具 点击下载 二.查看服务器 ip 地址命令 1.通过 ip addr 查看网卡 ip 地址 ip addr 2.通过 ifconfig 查看网卡 ip 地址 最小化安装 ...

  3. Python3基础 函数 多值参数 元组与字典形式(使用星号对列表与字典进行拆包)

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  4. 安装DEDECMS出现Function ereg_replace()错误的解决方法

    这个问题我记得以前有遇到的,是在本地调试dedecms整站程序的时候,从网上下载了一个整套程序包括模板到本地调试,导入数据库安装都正常,但是登陆 后台就出现"Deprecated: Func ...

  5. 泡泡一分钟:eRTIS - A Fully Embedded Real Time 3D Imaging Sonar Sensor for Robotic Applications

    eRTIS - A Fully Embedded Real Time 3D Imaging Sonar Sensor for Robotic Applications eRTIS  - 用于机器人应用 ...

  6. STM32---喜提点灯

    一:编译第一个程序 int main() //主函数 { } void SystemInit() //在执行主函数前,会被调用.不进行实现.在启动文件中被调用 { } ; Reset handler ...

  7. 【437】Binary search algorithm,二分搜索算法

    Complexity: O(log(n)) Ref: Binary search algorithm or 二分搜索算法 Ref: C 版本 while 循环 C Language scripts b ...

  8. LeetCode_278. First Bad Version

    278. First Bad Version Easy You are a product manager and currently leading a team to develop a new ...

  9. LeetCode_202. Happy Number

    202. Happy Number Easy Write an algorithm to determine if a number is "happy". A happy num ...

  10. Go micro 开发微服务步骤

    1.写 proto文件,定义接口和服务 2.实现 接口,注册 handle 3.调用服务:直接用rpc 客户端调用,或者用 api http web等调用 api http web 等服务可以对客户端 ...