阿里面试题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;}@Overridepublic 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 和 ChannelserverSocket.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 阶段是阻塞的,可以有效避免大量客户端连接时,频繁线程切换带来的问题,应用的扩展能力有了非常大的提高。下面这张图对这种实现思路进行了形象地说明。

(图片来源于杨晓峰)

四、参考资料

Java核心36讲

近期热门文章

Java 最常见的 200+ 面试题

如果你喜欢本文,扫描二维码关注微信公众号「王磊的博客」

公众号二维码

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

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

相关文章

机器翻译软件从实验室走向市场

机器翻译软件从实验室走向市场 冯志伟 机器翻译研究如何用计算机来进行不同自然语言之间的翻译&#xff0c;它是自然语言计算机处理的一个历史悠久的部门&#xff0c;是横跨语言学、数学、计算机科学的综合性学科&#xff0c;也是计算机软件应用的一个重要领域…

八、python编写IP地址计算第一个可用IP地址、最后一个可用IP地址、网络号、广播地址、主机数

# IP子网掩码转为子网掩码有多少个1的整数,例如:"255.255.255.0"有24个1 def strNetmask2nNetmask(strNetmask: str) -> int:result = ""print(strNetmask)for num in strNetmask.split(

CentOS7搭建离线部署Cloudera CDH 6.2.0大数据平台

如上述博客有任何错误或者疑问&#xff0c;请加VX&#xff1a;1755337994&#xff0c;及时告知&#xff01;万分感激&#xff01; 1.概述 CDH&#xff0c;全称Clouderas Distribution, including Apache Hadoop。是Hadoop众多分支中对应中的一种&#xff0c;由Cloudera维护&a…

负载均衡实现的几种方式

负载均衡&#xff0c;英文名Load Balance&#xff0c;作用是将操作分摊到多个执行单元上执行。随着如今网络流量的不断增大&#xff0c;服务的负载均衡是必须的&#xff0c;这里就来讲一讲负载均衡的结构。 说到负载均衡&#xff0c;同学最容易想到的可能就是nginx了&…

CheckBox as Image use button

为什么80%的码农都做不了架构师&#xff1f;>>> <CheckBox android:id"id/notificationPhoneIcon" android:layout_width"wrap_content" android:layout_height"wrap_content" android:layout_centerVertical"true" an…

1-1.Win10系统利用Pycharm社区版安装Django搭建一个简单Python Web项目的步骤之一

首先&#xff0c;安装python3.8和pycharm参考其他教程。 一、安装django 使用下面命令默认安装最新版的django pip install django也可以从django官网查看安装一个LTS长期稳定支持版本&#xff0c;从下图看到3.2是LTS版本&#xff0c;能够长期支持2021年&#xff5e;2024年&…

python装饰器函数传参

python装饰器函数传参 装饰器 装饰器是一个返回函数的高阶函数。 装饰器常见用法&#xff1a; 打印日志 def logger(func):def wrapper(*args, **kw):print do {}.format(func.__name__)func(*args, **kw)print finishreturn wrapperlogger def add(x,y):print {} {} {}.…

Tomcat工作原理及简单模拟实现

Tomcat应该都不陌生&#xff0c;我们经常会把写好的代码打包放在Tomcat里并启动&#xff0c;然后在浏览器里就能愉快的调用我们写的代码来实现相应的功能了&#xff0c;那么Tomcat是如何工作的&#xff1f;一、Tomcat工作原理我们启动Tomcat时双击的startup.bat文件的主要作用是…

苹果怎么调字体大小?详细教程在这,赶快get起来!

在我们使用苹果手机时&#xff0c;可能会遇到需要调整字体大小的情况。合适的字体大小能够提高阅读体验和舒适度&#xff0c;使得手机使用更加便捷。然而&#xff0c;还有很多用户并不知道苹果怎么调字体大小。别着急&#xff01;本文将为您详细介绍操作方法&#xff0c;帮助您…

javascript加载优化

1.将script放置在尽可能接近body标签底部的位置2.减少script总数3.defer 对应的script标签会被下载但不会被执行在onload句柄之前执行&#xff0c;但只兼容IE4 ff3.54.动态创建script 无论合适加载执行都不会影响页面加载转载于:https://www.cnblogs.com/qingw/p/3636304.html

PyQt5树形结构控件QTreeWidget操作

QTreeWidget 类根据预设的模型提供树形显示控件。 QTreeWidget 使用类似于 QListView 类的方式提供一种典型的基于 item 的树形交互方法类&#xff0c;该类基于QT的“模型/视图”结构&#xff0c;提供了默认的模型来支撑 item 的显示&#xff0c;这些 item 类为 QTreeWidgetIt…

Python3之logging输出写入日志

Python3之logging模块浅析 目录 Python3之logging模块浅析 简单用法日志与控制台同时输出 一个同时输出到屏幕、文件的完成例子日志文件截取日志重复打印问题解决 问题分析解决方案 1.使用不同的日志对象2.及时清理&#xff08;logger.handlers.clear&#xff09;3.使用前先判…

HashMap线程安全问题

HashMap是线程不安全的&#xff0c;在多线程环境下对某个对象中HashMap类型的实例变量进行操作时&#xff0c;可能会产生各种不符合预期的问题。本文详细说明一下HashMap存在的几个线程安全问题。注&#xff1a;以下基于JDK1.8HashMap原理请走传送门通过简单例子来探索HashMap原…

四、PyCharm PyQt5创建主窗口详细教程

1.打开PyCharm,新建工程MyMainTest 2.按照Tools-External Tools-QtDesigner,打开QT设计界面,保存窗体文件。

java8 lambda表达式实现自定义用户组件,Don't Repeat Yourself

2019独角兽企业重金招聘Python工程师标准>>> 一、用户组件的功能 使用java8 lambda表达式实现实现世界的一个例子&#xff1a;用户组件。此用户组件有以下几个操作&#xff1a;获取用户列表&#xff0c;获取单个用户&#xff0c;增加用户&#xff0c;删除用户&am…

如何在CDH5上部署Dolphin Scheduler 1.3.1

本文记录了在CDH5.16.2集群上集成Dolphin Scheduler 1.3.1的详细流程&#xff0c;特别注意一下MySQL数据库的连接串&#xff01; 1 文档编写目的 详细记录CDH5上Dolphin Scheduler 1.3.1的部署流程分布式部署Dolphin Scheduler 2 部署环境和依赖组件 为了适配CDH5上的Hive…

Kafka面试题全套整理 | 划重点要考!

做积极的人&#xff0c;而不是积极废人&#xff01;有很多人问过我要过Kafka相关的面试题&#xff0c;我一直懒得整理&#xff0c;这几天花了点时间&#xff0c;结合之前面试被问过的、别人咨询过的、我会问别人的进行了相关的整理&#xff0c;也就几十题&#xff0c;大家花个几…

PyQt5代码触发QTreeWidget的列表中某个item点击信号

https://blog.csdn.net/qq_37887537/article/details/80576844

【HDOJ】1068 Girls and Boys

匈牙利算法&#xff0c;最开始暴力解不知道为什么就是wa&#xff0c;后来明白&#xff0c;一定要求最优解。查了一下匈牙利算法相关内容&#xff0c;大致了解。 1 #include <stdio.h>2 #include <string.h>3 4 #define MAXNUM 5055 6 int map[MAXNUM][MAXNUM];7 in…

关于Java基础你不得不会的34个问题

目录1. 面向对象和面向过程的区别2. Java 语言有哪些特点3. 关于 JVM JDK 和 JRE 最详细通俗的解答4. Oracle JDK 和 OpenJDK 的对比5. Java和C的区别6. 什么是 Java 程序的主类 应用程序和小程序的主类有何不同7. Java 应用程序与小程序之间有那些差别8. 字符型常量和字符串常…