加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

架构师常识储蓄——深入领略BIO、NIO、AIO

发布时间:2019-10-18 21:06:57 所属栏目:建站 来源:咔咔侃技术
导读:本文你将获取到:同/异步 + 阻/非阻塞的机能区别;BIO、NIO、AIO 的区别;领略和实现 NIO 操纵 Socket 时的多路复用;同时把握 IO 最底层最焦点的操纵能力。 BIO、NIO、AIO 的区别是什么? 同/异步、阻/非阻塞的区别是什么? 文件读写最优雅的实现方法是什么? N

在 Java 中,线程的实现是较量重量级的,以是线程的启动可能烧毁是很耗损处事器的资源的,纵然行使线程池来实现,行使上述传统的 Socket 方法,当毗连数极具上升也会带来机能瓶颈,缘故起因是线程的上线文切换开销会在高并发的时辰浮现的很明明,而且以上操纵方法照旧同步阻塞式的编程,机能题目在高并发的时辰就会浮现的尤为明明。

以上的流程,如下图:

架构师常识储蓄——深入领略BIO、NIO、AIO

4.2 NIO 多路复用

介于以上高并发的题目,NIO 的多路复用成果就显自得义不凡了。

NIO 是操作了单线程轮询变乱的机制,通过高效地定位停当的 Channel,来抉择做什么,仅仅 select 阶段是阻塞的,可以有用停止大量客户端毗连时,频仍线程切换带来的题目,应用的扩展手段有了很是大的进步。

  1. // NIO 多路复用 
  2. ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 4, 
  3.  60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); 
  4. threadPool.execute(new Runnable() { 
  5.  @Override 
  6.  public void run() { 
  7.  try (Selector selector = Selector.open(); 
  8.  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();) { 
  9.  serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLocalHost(), port)); 
  10.  serverSocketChannel.configureBlocking(false); 
  11.  serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 
  12.  while (true) { 
  13.  selector.select(); // 阻塞守候停当的Channel 
  14.  Set<SelectionKey> selectionKeys = selector.selectedKeys(); 
  15.  Iterator<SelectionKey> iterator = selectionKeys.iterator(); 
  16.  while (iterator.hasNext()) { 
  17.  SelectionKey key = iterator.next(); 
  18.  try (SocketChannel channel = ((ServerSocketChannel) key.channel()).accept()) { 
  19.  channel.write(Charset.defaultCharset().encode("你好,天下")); 
  20.  } 
  21.  iterator.remove(); 
  22.  } 
  23.  } 
  24.  } catch (IOException e) { 
  25.  e.printStackTrace(); 
  26.  } 
  27.  } 
  28. }); 
  29. // Socket 客户端(吸取信息并打印) 
  30. try (Socket cSocket = new Socket(InetAddress.getLocalHost(), port)) { 
  31.  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(cSocket.getInputStream())); 
  32.  bufferedReader.lines().forEach(s -> System.out.println("NIO 客户端:" + s)); 
  33. } catch (IOException e) { 
  34.  e.printStackTrace(); 
  • 起首,通过 Selector.open() 建设一个 Selector,作为相同调治员的脚色;
  • 然后,建设一个 ServerSocketChannel,而且向 Selector 注册,通过指定 SelectionKey.OP_ACCEPT,汇报调治员,它存眷的是新的毗连哀求;
  • 为什么我们要明晰设置非阻塞模式呢?这是由于阻塞模式下,注册操纵是不应承的,会抛出 IllegalBlockingModeException 非常;
  • Selector 阻塞在 select 操纵,当有 Channel 产生接入哀求,就会被叫醒;

下面的图,可以有用的声名 NIO 复用的流程:

架构师常识储蓄——深入领略BIO、NIO、AIO

就这样 NIO 的多路复用就大大晋升了处事器端相应高并发的手段。

4.3 AIO 版 Socket 实现

Java 1.7 提供了 AIO 实现的 Socket 是这样的,如下代码:

  1. // AIO线程复用版 
  2. Thread sThread = new Thread(new Runnable() { 
  3.  @Override 
  4.  public void run() { 
  5.  AsynchronousChannelGroup group = null; 
  6.  try { 
  7.  group = AsynchronousChannelGroup.withThreadPool(Executors.newFixedThreadPool(4)); 
  8.  AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group).bind(new InetSocketAddress(InetAddress.getLocalHost(), port)); 
  9.  server.accept(null, new CompletionHandler<AsynchronousSocketChannel, AsynchronousServerSocketChannel>() { 
  10.  @Override 
  11.  public void completed(AsynchronousSocketChannel result, AsynchronousServerSocketChannel attachment) { 
  12.  server.accept(null, this); // 吸取下一个哀求 
  13.  try { 
  14.  Future<Integer> f = result.write(Charset.defaultCharset().encode("你好,天下")); 
  15.  f.get(); 
  16.  System.out.println("处事端发送时刻:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); 
  17.  result.close(); 
  18.  } catch (InterruptedException | ExecutionException | IOException e) { 
  19.  e.printStackTrace(); 
  20.  } 
  21.  } 
  22.  @Override 
  23.  public void failed(Throwable exc, AsynchronousServerSocketChannel attachment) { 
  24.  } 
  25.  }); 
  26.  group.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); 
  27.  } catch (IOException | InterruptedException e) { 
  28.  e.printStackTrace(); 
  29.  } 
  30.  } 
  31. }); 
  32. sThread.start(); 
  33. // Socket 客户端 
  34. AsynchronousSocketChannel client = AsynchronousSocketChannel.open(); 
  35. Future<Void> future = client.connect(new InetSocketAddress(InetAddress.getLocalHost(), port)); 
  36. future.get(); 
  37. ByteBuffer buffer = ByteBuffer.allocate(100); 
  38. client.read(buffer, null, new CompletionHandler<Integer, Void>() { 
  39.  @Override 
  40.  public void completed(Integer result, Void attachment) { 
  41.  System.out.println("客户端打印:" + new String(buffer.array())); 
  42.  } 
  43.  @Override 
  44.  public void failed(Throwable exc, Void attachment) { 
  45.  exc.printStackTrace(); 
  46.  try { 
  47.  client.close(); 
  48.  } catch (IOException e) { 
  49.  e.printStackTrace(); 
  50.  } 
  51.  } 
  52. }); 
  53. Thread.sleep(10 * 1000); 

五、总结

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读