ByteBuffer 大小分配

简介: ByteBuffer 大小分配
  • 每个 channel 都需要记录可能被切分的消息,因为 ByteBuffer 不能被多个 channel 共同使用,因此需要为每个 channel 维护一个独立的 ByteBuffer
  • ByteBuffer 不能太大,比如一个 ByteBuffer 1Mb 的话,要支持百万连接就要 1Tb 内存,因此需要设计大小可变的 ByteBuffer
  • 一种思路是首先分配一个较小的 buffer,例如 4k,如果发现数据不够,再分配 8k 的 buffer,将 4k buffer 内容拷贝至 8k buffer,优点是消息连续容易处理,缺点是数据拷贝耗费性能,参考实现 tutorials.jenkov.com/java-perfor…
  • 另一种思路是用多个数组组成 buffer,一个数组不够,把多出来的内容写入新的数组,与前面的区别是消息存储不连续解析复杂,优点是避免了拷贝引起的性能损耗

4.5 处理 write 事件

一次无法写完例子

  • 非阻塞模式下,无法保证把 buffer 中所有数据都写入 channel,因此需要追踪 write 方法的返回值(代表实际写入字节数)
  • 用 selector 监听所有 channel 的可写事件,每个 channel 都需要一个 key 来跟踪 buffer,但这样又会导致占用内存过多,就有两阶段策略
  • 当消息处理器第一次写入消息时,才将 channel 注册到 selector 上
  • selector 检查 channel 上的可写事件,如果所有的数据写完了,就取消 channel 的注册
  • 如果不取消,会每次可写均会触发 write 事件 public class WriteServer {
  • public static void main(String[] args) throws IOException { ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.configureBlocking(false); ssc.bind(new InetSocketAddress(8080));
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
    selector.select();
    Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        iter.remove();
        if (key.isAcceptable()) {
            SocketChannel sc = ssc.accept();
            sc.configureBlocking(false);
            SelectionKey sckey = sc.register(selector, SelectionKey.OP_READ);
            // 1. 向客户端发送内容
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 3000000; i++) {
                sb.append("a");
            }
            ByteBuffer buffer = Charset.defaultCharset().encode(sb.toString());
            int write = sc.write(buffer);
            // 3. write 表示实际写了多少字节
            System.out.println("实际写入字节:" + write);
            // 4. 如果有剩余未读字节,才需要关注写事件
            if (buffer.hasRemaining()) {
                // read 1  write 4
                // 在原有关注事件的基础上,多关注 写事件
                sckey.interestOps(sckey.interestOps() + SelectionKey.OP_WRITE);
                // 把 buffer 作为附件加入 sckey
                sckey.attach(buffer);
            }
        } else if (key.isWritable()) {
            ByteBuffer buffer = (ByteBuffer) key.attachment();
            SocketChannel sc = (SocketChannel) key.channel();
            int write = sc.write(buffer);
            System.out.println("实际写入字节:" + write);
            if (!buffer.hasRemaining()) { // 写完了
                key.interestOps(key.interestOps() - SelectionKey.OP_WRITE);
                key.attach(null);
            }
        }
    }
}
  • } }

客户端 public class WriteClient { public static void main(String[] args) throws IOException { Selector selector = Selector.open(); SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); sc.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ); sc.connect(new InetSocketAddress("localhost", 8080)); int count = 0; while (true) { selector.select(); Iterator iter = selector.selectedKeys().iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); iter.remove(); if (key.isConnectable()) { System.out.println(sc.finishConnect()); } else if (key.isReadable()) { ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); count += sc.read(buffer); buffer.clear(); System.out.println(count); } } } } }


目录
相关文章
|
9月前
|
存储 分布式计算 数据库
ETL vs ELT:到底谁更牛?别被名字骗了,这俩是两种世界观
ETL vs ELT:到底谁更牛?别被名字骗了,这俩是两种世界观
401 12
|
SQL Java 数据库连接
Hive教程(08)- JDBC操作Hive
Hive教程(08)- JDBC操作Hive
2053 0
|
8月前
|
缓存 安全 Java
探索并发编程中ConcurrentHashMap的使用
综上所述,ConcurrentHashMap是Java并发编程中不可或缺的一部分,它通过与操作系统、JVM及硬件特性紧密结合,为开发高效且线程安全的并发应用程序提供了强大的数据结构支持。掌握ConcurrentHashMap的使用是实现高性能并发程序的关键步骤之一。
303 117
|
6月前
|
人工智能 自然语言处理 API
AI Agent 职业路线全解析:从入门到专家的能力图谱与进阶路径
大模型正从文本生成迈向AI Agent时代,核心范式由“预测下一个词”升级为“预测下一个动作”。AI Agent工程师聚焦自主闭环系统构建,需掌握推理框架、记忆设计、API集成与多智能体协作四大能力,职业路径覆盖应用层、系统层到专家层,是认知自动化与下一代软件工程的核心赛道。(239字)
673 2
|
Dubbo Java 应用服务中间件
Dubbo两小时快速上手教程(直接代码、Spring、SpringBoot)
最近项目中需要用到dubbo,虽然我知道dubbo是一个RPC框架,但是没有去详细了解这个框架。既然项目要用,那就先把Dubbo的应用给学会,等熟练使用之后,再去了解Dubbo内部的原理。如果想要项目代码,直接联系我即可。如果想要demo代码,直接联系我即可。
8762 1
|
人工智能 Java 测试技术
JDK11下Mock框架进化:从PowerMockito到Mockito Only
本文探讨了从使用PowerMock的测试环境迁移到仅使用Mockito(Mockito Only)策略的必要性和实践方法。
936 10
|
Java Spring 容器
Java获取接口的所有实现类方法
这篇文章介绍了在Java中获取接口所有实现类的方法,包括使用JDK的ServiceLoader(SPI机制)和Spring Boot中的@Autowired自动注入及ApplicationContextAware接口两种方式。
1986 1
|
存储 监控 Java
(十一)彻悟并发之JUC分治思想产物-ForkJoin分支合并框架原理剖析上篇
在上篇文章《深入理解并发之Java线程池、工作原理、复用原理及源码分析》中,曾详细谈到了Java的线程池框架。在其中也说到了JDK提供的四种原生线程池以及自定义线程池,而本文则再来详细谈谈JDK1.7中新推出的线程池:ForkJoinPool。
399 1
|
人工智能 自然语言处理 测试技术
通义灵码多维度体验分享
一文带你多维度了解通义灵码
1493 4
|
开发框架 Java 数据库
Spring Boot集成多数据源的最佳实践
Spring Boot集成多数据源的最佳实践

热门文章

最新文章