首页 > 编程语言 >Java 网络编程 —— 异步通道和异步运算结果

Java 网络编程 —— 异步通道和异步运算结果

时间:2023-05-21 12:44:36浏览次数:35  
标签:异步 Java pingResult 编程 Future msg pingResults public

从 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,pingResult,编程,Future,msg,pingResults,public
From: https://www.cnblogs.com/Yee-Q/p/17418459.html

相关文章

  • java数据类型
    题目: 题解:float数据值必须加f ,否则就得强转   同理Double数据也是这样 要么强转 要么数值加小写字母d,指明这是一个双精度浮点值   而\u开头的unicode字符串,是可以直接赋值给char的 String会自动装箱成包装类,就可以向上转型成Object了 ......
  • Java的CAS操作
    介绍CAS技术是为了解决问题而生的,通过CAS我们可以以无锁的方式,保证对共享数据进行“读取-修改-写回”操作序列的正确性。CAS是乐观锁设计思想的实现。CAS的思想是:在“读取-修改-写回”操作序列中,先读取并修改数据,写回数据前先判断读取数据后的这段时间内数据是否......
  • Java二叉树详解
    当你看到一棵茂盛的大树时,你是否曾想过这样的问题:它是如何生长起来的?落叶归根,数百年来,不断地生长与死亡。其实,每个程序员也可以成为一棵大树的缔造者。而Java的二叉树,就像互联网上的知识一样,通过它的枝干和叶子,能够让我们更加高效地搜索、插入和删除节点。虽然二叉树算法并不简单......
  • Java 拦截器和过滤器
    1.java后端基于过滤器或拦截器处理跨域请求 Java中的过滤器和拦截器的区别Java中的拦截器和过滤器有什么区别 springmvc执行流程? Action就是用于处理一次用户请求的对象。什么是Servlet容器? Servlet 容器只不过是一个Java程序。 ......
  • Python高级编程技巧:函数式编程和闭包
    Python是一种非常流行的编程语言,可以用于各种应用领域,如Web开发,人工智能,数据科学等。其中,函数式编程和闭包是Python编程中非常重要的概念,本文将深入探讨这两个主题。函数式编程Python是一种多范式语言,既支持面向对象编程,也支持函数式编程。函数式编程的一大特点是强调函数的纯洁性......
  • JavaScript基础知识笔记
    JavaScript是属于Web的编程语言,对网页行为进行编程。参考教程:https://www.w3school.com.cn/js/index.asphttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Language_overviewJavaScript能够改变HTML内容document.getElementById("demo").innerHTML="Hell......
  • java-求余数计算
    publicclassTest521929{  publicstaticvoidmain(String[]args){    System.out.println(100%3); //1     //算术表达式2个参数为整数,返回结果也是整数    System.out.println(100%3.0); //1.0    System.out.println(100.......
  • 在java中使用lua脚本操作redis
    前言众所周知,redis可以执行lua脚本,至于为什么要用lua脚本来操作redis,自行百度咯开始Bean类packagecn.daenx.myadmin.common.config.redis;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.......
  • Java-Day-23( 线程二:线程终止 + 常用方法 + 用户线程 + 守护线程 + 线程生命周期 + Syn
    Java-Day-23线程终止setLoop()基本说明当线程完成任务后,会自动退出还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式练习使用publicclasstest1{publicstaticvoidmain(String[]args)throwsInterruptedException{Tt1=newT();......
  • Java 网络编程 —— 实现非阻塞式的客户端
    创建阻塞的EchoClient客户程序一般不需要同时建立与服务器的多个连接,因此用一个线程,按照阻塞模式运行就能满足需求publicclassEchoClient{privateSocketChannelsocketChannel=null;publicEchoClient()throwsIOException{socketChannel......