java aio 网络编程 服务端
程序员文章站
2022-03-20 18:28:14
...
今天测试了一下AsynchronousServerSocketChannel进行网络编程,发现这个效率确实高。讲一下测试场景,AsynchronousServerSocketChannel监听连接,获取到连接以后,提交给线程池去执行任务。一开始有些地方比较迷惑,比如启动一个5个线程的连接池,当我有10个连接进来,按照每一个连接都会封装成任务的做法,岂不是有五个一开始会等待,直到之前的五个中有任务执行完了,剩余的五个任务才会陆续执行,这样的话,为什么人们都说它效率高呢?
反正我一开始是有这个想法,于是我写了个测试,验证我的想法,发现并不是我想的那样,先看看代码,然后再详细说明一下。
package com.pzn.aio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class AioServer { public static void main(String[] args) throws IOException, InterruptedException, ExecutionException { // ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); // AsynchronousServerSocketChannel boss = AsynchronousServerSocketChannel.open(); boss.bind(new InetSocketAddress("127.0.0.1", 9000)); while (true) { System.out.println("active thread... " + pool.getActiveCount()); AsynchronousSocketChannel worker = boss.accept().get(); System.out.println("accepted a new connect."); pool.submit(new Task(worker)); } } }
package com.pzn.aio; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.TimeUnit; public class Task implements Runnable { private final AsynchronousSocketChannel worker; public Task(AsynchronousSocketChannel worker) { this.worker = worker; } public void run() { try { worker.write(ByteBuffer.wrap("i am server.".getBytes("utf-8")), null, new CompletionHandler<Integer, Object>() { public void completed(Integer result, Object attachment) { try { TimeUnit.SECONDS.sleep(5); System.out.println("write completed."); worker.close(); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void failed(Throwable exc, Object attachment) { System.out.println("write failed."); } }); System.out.println(Thread.currentThread() + " execute Asynchronous task."); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }
Task这个任务中,调用AsynchronousSocketChannel的write方法使用异步的方式,最后一个参数是回调,当server写数据完成后,会执行回调中的方法,我在回调方法completed中睡眠5秒时为了观察效果,看看线程池是否可以超过5个任务同时连接。
结果表明,是可以的。实际上这个Task的run方法会立即执行完,根本不会去管回调中的睡眠时间,这样就相当于线程池会马上有空闲线程来处理新的连接,当然还是有一点的延迟,但不至于延迟等待5秒。特别要注意的是:执行回掉的方法,这个就不是我们所能干预的了,依赖操作系统的机制来进入回调,回调方法的执行已经和线程池没有关系了,因为所有提交的Task的run方法都已经执行结束了。