0

0

Java中关于非阻塞I/O的使用方法

黄舟

黄舟

发布时间:2017-09-29 09:58:37

|

1781人浏览过

|

来源于php中文网

原创

这篇文章主要介绍了java 非阻塞i/o使用方法,文中涉及非阻塞i/o的简介,同时向大家展示了利用非阻塞i/o实现客户端的方法,需要的朋友可以参考下。

绝大部分知识与实例来自O'REILLY的《Java网络编程》(Java Network Programming,Fourth Edition,by Elliotte Rusty Harold(O'REILLY))。

非阻塞I/O简介

非阻塞I/O(NIO)是处理高并发的一种手段。在高并发的情况下,创建和回收线程以及在线程间切换的开销变得不容忽视,此时就可以使用非阻塞I/O技术。这种技术的核心思想是每次选取一个准备好的连接,尽快地填充这个连接所能管理的尽可能多的数据,然后转向下一个准备好的连接。

利用非阻塞I/O实现的客户端

立即学习Java免费学习笔记(深入)”;

一般情况下,客户端不会需要处理很高数量的并发连接。事实上,非阻塞I/O主要是为服务器设计的,但它也可以用在客户端上。由于客户端的设计相比服务器容易,因此下面先用客户端来进行简单演示。

首先介绍通道(channel)和缓冲区。非阻塞I/O中使用SocketChannel类创建连接。要获取SocketChannel对象,需要将一个SocketAddress对象(通常会使用它的子类InetSocketAddress)传入它的静态工厂方法open()中。下面为一个示例:


SocketAddress address = new InetSocketAddress("127.0.0.1", 19);
SocketChannel client = SocketChannel.open(address);

open()方法是阻塞的,因此这之后的代码在连接建立之前不会执行。如果连接无法建立,会抛出一个IOException异常。

连接建立之后就需要获取输入和输出。不同于传统的getInputStream()与getOutputStream(),利用通道,你可以直接写入通道本身。不是写入字节数组,而是要写入一个ByteBuffer对象。ByteBuffer对象通过ByteBuffer.allocate(int capacity)获取,capacity为缓冲区大小,单位为字节:


ByteBuffer buffer = ByteBuffer.allocate(74);

获得ByteBuffer对象后,将其传递给SocketChannel对象的read()方法,SocketChannel对象会用从Socket读取的数据填充这个缓冲区。read()方法返回成功读取并储存在缓冲区中的字节数。默认情况下,它会至少读取一个字节,或者返回-1指示数据结束,没有字节可用时阻塞。这与InputStream的行为大致相同。但如果设置成非阻塞模式,没有字节可用时它会立即返回0,不会阻塞。

简单实用的Bootstrap选项卡效果
简单实用的Bootstrap选项卡效果

这是一款基于Bootstrap的简单实用的选项卡效果。该选项卡在原生boostrap选项卡的基础上进行了一些美化,效果时尚大方,非常不错。 使用方法 在页面中引入jquery和bootstrap相关文件。

下载

现在假定缓冲区内已经有了一些数据,之后就需要将它们提取出来。可以使用传统的方式,先将数据写入一个字节数组,之后再写入一个输出流中。这里介绍一种完全基于通道的方法:利用Channels工具类将输出流封装到一个通道中:


WritableByteChannel out = Channels.newChannel(System.out);

上面的代码将System.out封装入一个通道中。这之后就可以进行输出了。ByteBuffer对象在每次输出之前,需要调用一下它的flip()方法,使得通道从开头开始读。在读写完毕后,还需要调用它的clear()方法,重置缓冲区的状态。下面是进行一次数据输出的代码:


buffer.flip();
out.write(buffer);
buffer.clear();

实例1:利用非阻塞I/O实现的CharGenerator(字符生成器)客户端

服务器代码:


public static void createCharGeneratorServer(){
  try(ServerSocket server = new ServerSocket(19)){
    while(true){
      try(Socket connection = server.accept()){
        OutputStream out = connection.getOutputStream();
        int firstPrintableCharacter = 33;
        int numberOfPrintableCharacter = 94;
        int numberOfCharactersPerLine = 72;
        int start = firstPrintableCharacter;
        while(true){
          for(int i = start ;
              i < start + numberOfCharactersPerLine ; i++){
            out.write
            (firstPrintableCharacter + (i - firstPrintableCharacter) % numberOfPrintableCharacter);
          }
          out.write('\r');
          out.write('\n');
          start = firstPrintableCharacter + (start + 1 - firstPrintableCharacter) % numberOfPrintableCharacter;
        }
      }catch (IOException e) {
        e.printStackTrace();
      }
    }
  } catch (IOException e) {
    e.printStackTrace();
  }
}

客户端代码:


try {
  SocketAddress address = new InetSocketAddress("127.0.0.1", 19);
  SocketChannel client = SocketChannel.open(address);
  ByteBuffer buffer = ByteBuffer.allocate(74);
    WritableByteChannel out = Channels.newChannel(System.out);
  while(client.read(buffer) != -1){
    buffer.flip();
    out.write(buffer);
    buffer.clear();
  }
} catch (IOException e) {
  e.printStackTrace();
}
输出(无限循环):
]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEF
^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFG
_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGH
`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI
abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ
bcdefghijklmnopqrstuvwxyz{|}~!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK

启用非阻塞模式

上面的程序和使用输入/输出流的传统方式并没有太大差别。不过,可以调用ServerSocket的configureBlocking(false)方法将其设置为非阻塞模式。这个模式下,如果没有可用的数据,read()方法会立即返回,这让客户端可以去做其他事情。不过,由于read()方法在读不到数据时会返回0,读取数据的循环需要做一些改动:


while(true){
  //这里可以写每次循环都要做的事,无论有没有读到数据
  int n = client.read(buffer);
  if(n > 0){
    buffer.flip();
    out.write(buffer);
    buffer.clear();
  }else if (n == -1) {
    //除非服务器故障,否则不会发生
    break;
  }
}

总结

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

12

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

4

2026.01.30

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

20

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

18

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

19

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

3

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 8万人学习

Java 教程
Java 教程

共578课时 | 53.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号