阿里面试题BIO和NIO数量问题附答案和代码
一、问题
BIO 和 NIO 作为 Server 端,当建立了 10 个连接时,分别产生多少个线程?
答案: 因为传统的 IO 也就是 BIO 是同步线程堵塞的,所以每个连接都要分配一个专用线程来处理请求,这样 10 个连接就会创建 10 个线程去处理。而 NIO 是一种同步非阻塞的 I/O 模型,它的核心技术是多路复用,可以使用一个链接上的不同通道来处理不同的请求,所以即使有 10 个连接,对于 NIO 来说,开启 1 个线程就够了。
二、BIO 代码实现
public class DemoServer extends Thread {
private ServerSocket serverSocket;
public int getPort() {
return serverSocket.getLocalPort();
}
public void run() {
try {
serverSocket = new ServerSocket(0);
while (true) {
Socket socket = serverSocket.accept();
RequestHandler requestHandler = new RequestHandler(socket);
requestHandler.start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
DemoServer server = new DemoServer();
server.start();
try (Socket client = new Socket(InetAddress.getLocalHost(), server.getPort())) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
bufferedReader.lines().forEach(s -> System.out.println(s));
}
}
}
// 简化实现,不做读取,直接发送字符串
class RequestHandler extends Thread {
private Socket socket;
RequestHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try (PrintWriter out = new PrintWriter(socket.getOutputStream());) {
out.println("Hello world!");
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 服务器端启动 ServerSocket,端口 0 表示自动绑定一个空闲端口。
- 调用 accept 方法,阻塞等待客户端连接。
- 利用 Socket 模拟了一个简单的客户端,只进行连接、读取、打印。
- 当连接建立后,启动一个单独线程负责回复客户端请求。
这样,一个简单的 Socket 服务器就被实现出来了。
(图片来源于杨晓峰)
三、NIO 代码实现
public class NIOServer extends Thread {
public void run() {
try (Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();) {// 创建 Selector 和 Channel
serverSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 8888));
serverSocket.configureBlocking(false);
// 注册到 Selector,并说明关注点
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();// 阻塞等待就绪的 Channel,这是关键点之一
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
// 生产系统中一般会额外进行就绪状态检查
sayHelloWorld((ServerSocketChannel) key.channel());
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void sayHelloWorld(ServerSocketChannel server) throws IOException {
try (SocketChannel client = server.accept();) { client.write(Charset.defaultCharset().encode("Hello world!"));
}
}
// 省略了与前面类似的 main
}
- 首先,通过 Selector.open() 创建一个 Selector,作为类似调度员的角色。
- 然后,创建一个 ServerSocketChannel,并且向 Selector 注册,通过指定 SelectionKey.OP_ACCEPT,告诉调度员,它关注的是新的连接请求。注意:为什么我们要明确配置非阻塞模式呢?这是因为阻塞模式下,注册操作是不允许的,会抛出 IllegalBlockingModeException 异常。
- Selector 阻塞在 select 操作,当有 Channel 发生接入请求,就会被唤醒。
- 在 sayHelloWorld 方法中,通过 SocketChannel 和 Buffer 进行数据操作,在本例中是发送了一段字符串。
可以看到,在前面两个样例中,IO 都是同步阻塞模式,所以需要多线程以实现多任务处理。而 NIO 则是利用了单线程轮询事件的机制,通过高效地定位就绪的 Channel,来决定做什么,仅仅 select 阶段是阻塞的,可以有效避免大量客户端连接时,频繁线程切换带来的问题,应用的扩展能力有了非常大的提高。下面这张图对这种实现思路进行了形象地说明。
(图片来源于杨晓峰)
四、参考资料
近期热门文章
关注下面二维码,订阅更多精彩内容。
阿里面试题BIO和NIO数量问题附答案和代码的更多相关文章
- C语言面试题(嵌入式开发方向,附答案及点评)
整理自C语言面试题(嵌入式开发方向,附答案及点评) 预处理器(Preprocessor) 1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SEC ...
- 九道大型软件公司.net面试题!一定得看(附答案)
1:a=10,b=15,在不用第三方变量的前提下,把a,b的值互换 2:已知数组int[] max={6,5,2,9,7,4,0};用快速排序算法按降序对其进行排列,并返回数组 3:请简述面向 ...
- Android面试题总结(不定期更新、附答案)
1.Activity的启动模式? activity一共有4种启动模式:standard.singleTop singleTask .singleInstance standard:(标准模式)默认的就 ...
- Objective-C面试题(精心整理的,附答案)
转自:http://www.mianwww.com/html/2014/03/20372.html 1.objective-c 是所有对象间的交互是如何实现的? 在对象间交互中每个对象承担的角色不同, ...
- Java开发工程师最新面试题库系列——Mybatis框架部分(附答案)
Mybatis Mybatis是什么框架? 答:持久层框架 Mybatis和ORM有什么区别? 答:ORM是对象关系映射的一种设计理念,也就是对象属性对应数据库字段,让开发人员以操作对象的方式操作数据 ...
- 基础 | BIO、NIO与AIO
本文链接:https://blog.csdn.net/bingbeichen/article/details/83617163 Java中的IO部分比较复杂,具体可参看书籍<Java NIO&g ...
- 操作系统层面聊聊BIO,NIO和AIO (epoll)
BIO 有了Block的定义,就可以讨论BIO和NIO了.BIO是Blocking IO的意思.在类似于网络中进行read, write, connect一类的系统调用时会被卡住. 举个例子,当用re ...
- Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)
本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为 ...
- BIO 和 NIO
一.阻塞(Block)和非阻塞(NonBlock) 阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,当数据没有准备的时候阻塞: 阻塞:往往需要等待缞冲区中的数据准备好过后才处理其他 ...
随机推荐
- 计算机网络通信TCP/IP协议浅析 网络发展简介(二)
本文对计算机网络通信的原理进行简单的介绍 首先从网络协议分层的概念进行介绍,然后对TCP.IP协议族进行了概念讲解,然后对操作系统关于通信抽象模型进行了简单介绍,最后简单描述了socket 分层的 ...
- 【Node.js】利用node.js搭建服务器并访问静态网页
node.js是一门服务端的语言,下面讲讲如何利用node.js提供给我们的api来搭建服务器,并且访问静态网页 项目结构如下 ------------------------------------ ...
- WPF 语言格式化文本控件
前言 本章讲述正确添加语言资源的方式,以及一段语言资源的多种样式显示. 例如:“@Winter,你好!感谢已使用软件 800 天!” 在添加如上多语言资源项时,“XX,你好!感谢已使用软件 X 天!” ...
- python3中json模块的用法
__author__ = "JentZhang" import json user_info = {"} # 将字典转换为JSON字符串 json_str = json. ...
- FastReport编程方式给Picture控件赋值
public Image BytesToImage(Byte[] buffer) { var ms = new MemoryStream(buffer, 0, buffer.Length); retu ...
- 【微服务No.2】polly微服务故障处理库
熔断.降级: 熔断:熔断就是我们常说的“保险丝”,意为当服务出现某些状况时,切断服务,从而防止应用程序不断地常识执行可能会失败的操作造成系统的“雪崩”,或者大量的超时等待导致系统卡死等情况,很多地方也 ...
- Android开发——Notification通知的使用及NotificationCopat.Builder常用设置API
想要看全部设置的请看这一篇 [转]NotificationCopat.Builder全部设置 常用设置: 设置属性 说明 setAutoCancel(boolean autocancel) 设置点击信 ...
- Django学习之一:Install Djongo 安装Djongo
Install Djongo 安装Djongo Djongo是基于python的web框架,自然安装最关心的是python解释器版本了. Prerequisites 安装条件 Python版本与Djo ...
- CSS变量(自定义属性)实践指南
本文翻译自:https://www.sitepoint.com/practical-guide-css-variables-custom-properties/ 转载请注明出处:葡萄城官网,葡萄城为开 ...
- JAVA项目从运维部署到项目开发(三.Redis)
一.Redis的介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.它通常被称为数据结构服务器,因为值(va ...