从 JDK7 开始,引入了表示异步通道的 AsynchronousSockerChannel 类和 AsynchronousServerSocketChannel 类,这两个类的作用与 SocketChannel 类和 ServerSockelChannel 相似,区别在于异步通道的一些方法总是采用非阻塞模式,并且它们的非阻塞方法会立即返回一个 Future 对象,用来存放方法的异步运算结果

AsynchronousSocketChannel 类有以下非阻塞方法:

// 连接远程主机
Future<Void> connect(SocketAddress remote);
// 从通道中读入数据,存放到ByteBuffer中
// Future对象包含了实际从通道中读到的字节数
Future<Inleger> read(ByteBuffer dst);
// 把ByteBuffer的数据写入通道
// Future对象包含了实际写入通道的字节数
Future<Integer> write(ByteBuffer src);

AsynchronousServerSocketChannel 类有以下非阻塞方法:

// 接受客户连接请求
// Future对象包含连接建立成功后创建的AsynchronousSockelChannel对象
Future<AsynchronousSocketChannel> accept();

使用异步通道,可以使程序并行执行多个异步操作,例如:

SocketAddress socketAddress = ...;
AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); //请求建立连接
Future<Void> connected = client.connect(socketAddress);
ByteBuffer byteBuffer = ByteBuffer.allocate(128); //执行其他操作
//... //等待连接完成
connected.get(); //读取数据
Future<Integer> future = client.read(byteBuffer); //执行其他操作
//... //等待从通道读取数据完成
future.get(); byteBuffer.flip();
WritableByteChannel out = Channels.newChannel(System.out);
out.write(byteBuffer);

下例的代码演示了异步通道的用法,它不断接收用户输入的域名并尝试建立连接,最后打印建立连接所花费的时间。如果程序无法连接到指定的主机,就打印相关错误信息。如果用户输入 bye,就结束程序

//表示连接一个主机的结果
class PingResult { InetSocketAddress address;
long connectStart; //开始连接时的时间
long connectFinish = 0; //连接成功时的时间
String failure;
Future<Void> connectResult; //连接操作的异步运算结果
AsynchronousSocketChannel socketChannel;
String host;
final String ERROR = "连接失败"; PingResult(String host) {
try {
this.host = host;
address = new InetSocketAddress(InetAddress.getByName(host), 80);
} catch (IOException x) {
failure = ERROR;
}
} //打印连接一个主机的执行结果
public void print() {
String result;
if (connectFinish != 0) {
result = Long.toString(connectFinish - connectStart) + "ms";
} else if (failure != null) {
result = failure;
} else {
result = "Timed out";
}
System,out,println("ping "+ host + "的结果" + ":" + result);
} public class PingClient {
//存放所有PingResult结果的队列
private LinkedList<PingResult> pingResults = new Linkedlist<PingResult>();
boolean shutdown = false;
ExecutorService executorService; public PingClient() throws IOException {
executorService = Executors.newFixedThreadPool(4);
executorService.execute(new Printer());
receivePingAddress();
}
} public static void main(String args[]) throws IOException {
new PingClient();
} /*接收用户输入的主机地址,由线程池执行PingHandler任务 */
public void receivePingAddress() {
try {
BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
//接收用户输入的主机地址
while((msg = localReader.readLine()) != null) {
if(msg.equals("bye")) {
shutdown = true;
executorService.shutdown();
break;
}
executorService.execute(new PingHandler(msg));
}
} catch(IOException e) {}
} /* 尝试连接特定主机,生成一个PingResult对象,把它加入PingResults结果队列中 */
public class PingHandler implements Runnable {
String msg;
public PingHandler(String msg) {
this.msg = msg;
}
public void run() {
if(!msg.equals("bye")) {
PingResult pingResult = new PingResult(msg);
AsynchronousSocketChannel socketChannel = null;
try {
socketChannel = AsynchronousSocketChannel.open();
pingResult.connectStart = System.currentTimeMillis();
synchronized (pingResults) {
//向pingResults队列加入一个PingResult对象
pingResults.add(pingResult);
pingResults,notify();
}
Future<Void> connectResult = socketChannel.connect(pingResult.address);
pingResult.connectResult = connectResult;
} catch (Exception x) {
if (socketChannel != null) {
try { socketChannel.close();} catch (IOException e) {)
}
pingResult.failure = pingResult.ERROR;
}
}
}
} /* 打印PingResults结果队列中已经执行完毕的任务的结果 */
public class Printer implements Runnable {
public void run() {
PingResult pingResult = null;
while(!shutdown) {
synchronized (pingResults) {
while (!shutdown && pingResults.size() == 0 ) {
try {
pingResults.wait(100);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
if(shutdown && pingResults.size() == 0 ) break;
pingResult = pingResults.getFirst(); try {
if(pingResult.connectResult != null) {
pingResult.connectResult.get(500, TimeUnit,MILLISECONDS);
} catch(Exception e) {
pingResult.failure = pingResult.ERROR;
}
} if(pingResult.connectResult != null && pingResult.connectResult.isDone()) {
pingResult.connectFinish = System.currentTimeMillis();
} if(pingResult,connectResult != null && pingResult.connectResult.isDone() || || pingResult,failure != null) {
pingResult.print();
pingResults.removeFirst();
try {
pingResult.socketChannel.close();
} catch (IOException e) {}
}
}
}
}
}
}

PingClient 类定义了两个表示特定任务的内部类:

  • PingHandler:负责通过异步通道去尝试连接客户端输入的主机地址,并且创建一个 PingResult 对象,它包含了连接操作的异步运算结果,再将其加入 PingResults 结果队列
  • Printer:负责打印 PingResults 结果队列已经执行完毕的任务结果,打印完毕的 PingResult 对象会从队列中删除

Java 网络编程 —— 异步通道和异步运算结果的更多相关文章

  1. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  2. Java网络编程基础(Netty预备知识)

    今天在家休息,闲来无事,写篇博客,陶冶下情操~~~ =================我是分割线================ 最近在重新学习Java网络编程基础,以便后续进行Netty的学习. 整 ...

  3. Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...

  4. Java网络编程和NIO详解3:IO模型与Java网络编程模型

    Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...

  5. Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)

    本文转载 https://www.javadoop.com 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c ...

  6. Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型

    本文转自:http://www.sohu.com/a/203838233_827544 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 ht ...

  7. 这份书单会告诉你,Java网络编程其实很重要

  8. Java 网络编程学习总结

    新手一枚,Java学习中,把自己学习网络编程的知识总结一下,梳理下知识,方便日后查阅,高手莫进. 本文的主要内容: [1]    网络编程认识                [2]  TCP/IP编程 ...

  9. 【Android实战】----从Retrofit源代码分析到Java网络编程以及HTTP权威指南想到的

    一.简单介绍 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明确为什么Retrofit那么屌. 近期也看了一些其源代码分析的文章以及亲自查看了源代码 ...

  10. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

随机推荐

  1. OpenGL 摄像机视角详解

    1. 摄像机 摄像机就好像是我们的眼睛,我们从摄像机的方向观察世界空间中的模型.摄像机远离模型,模型自然就变小了(透视投影下),然而,在GL中事实上并没有摄像机的概念.但是我们可以通过移动世界空间远离 ...

  2. IDEA编译器的永久试用设置与基本使用

    参考视频: 最通俗易懂的JDK.IDEA的安装使用权威指南 2023新版前端Web开发HTML5+CSS3+移动web视频教程,前端web入门首选黑马程序员 一.安装包下载与安装 官网下载地址 个人使 ...

  3. Java API 操作Docker浅谈

    背景: 使用com.github.docker-java库可以很方便地在Java中操作Docker.下面是一个详细的教程,包括创建镜像.创建容器.启动容器.停止容器和删除容器的步骤以及每一步的说明. ...

  4. 51Nod 1085 01背包

    01背包入门题,刚学完当写模板. 在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2--Wn(Wi为整数),与之相对应的价值为P1,P2--Pn(Pi为整数).求背包能够容纳的最大价 ...

  5. Oracle-lsnrctl监听进程控制

    LSNRCTL> help The following operations are available An asterisk (*) denotes a modifier or extend ...

  6. Reformer 模型 - 突破语言建模的极限

    Reformer 如何在不到 8GB 的内存上训练 50 万个词元 Kitaev.Kaiser 等人于 20202 年引入的 Reformer 模型 是迄今为止长序列建模领域内存效率最高的 trans ...

  7. Tomcat自动化脚本

    /bin/bash war包名称 war_name="tchg.war" 要上传war包指定目录 war_dir="/usr/local/src/tchg" 工 ...

  8. MyBatisPlus-使用步骤

    MyBatisPlus-使用步骤 第一步 引入maven坐标依赖 <dependency> <groupId>com.baomidou</groupId> < ...

  9. MinIO客户端之rm

    MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc rm 删除指定的对象. 准备待删除的对象,查看对象,命令如下: ./mc ls local1/bkt2/ 控 ...

  10. Python——第四章:推导式(Comprehensions)

    推导式: 推导式是为了简化代码. 语法: 列表推导式:[数据 for循环 if判断] 集合推导式:{数据 for循环 if判断} 字典推导式:{k:v for循环 if判断} 元组推导式:不存在(因为 ...