把Java的nio坑逐个踩一遍

简介:

        epoll是个好东西好多地方都在直接或间接的用,nginx用event库用nio用你用我用大家用。LT模式省心ET模式牛掰,处理得当效率那真是杠杠的,C、C++的用法可以参考“项目”通用库https://git.oschina.net/gonglibin/GlbLib-1.0.0中的封装,也可以参考“代码片段”中的用例https://git.oschina.net/gonglibin/codes/kev675liw8unz3j4psft134。由于一个潜在的项目迁移计划导致未来存在基于java技术路线中涉及线程池大并发长(短)连接的业务,所以一个框架就显得特别重要,兵马未动粮草先行。其实不同的业务包含各自不同的应用场景,就通信而言其实差别有时候还是挺大的,同样TCP连接,有的长有的短,有的求多应少,有的求少应多,还有一问一答的,更有一言不合就shutdown的,对底层资源的管理不上心有时候真不行,大半夜没起过夜绝对不算老司机。

        说说nio踩过的坑吧,下面列举的仅仅是让发动机托底的大坑,其中崴脚的小坑更是不计其数,首先打开地址https://git.oschina.net/gonglibin/codes/2jagu36pq7dwsc1eylkr916。首先注意一点的是nio的许多操作不是线程安全的,用不对各种坑有的踩了。大致思路首先创建TCP服务,构造里建线程池,主进程里给selector对象画个圈圈,这个对象的所有操作限制在listen方法里,把对业务的处理全部浸泡在读事件中,为啥读完不注册写信号让写事件处理呢,一会后面说吧,要是忘了千万别提醒我。

        坑一,cli.register(sel, SelectionKey.OP_READ, ByteBuffer.allocate(TU_SERSIZE)),在注册新连接的时候顺带把allocate的buffer赋值给SelectionKey对象的attachment,接下来read并判断读取长度,不大于零和对端一起关闭,否则把SelectionKey对象往线程池里一派发就完事了,流程自己继续跑它自己的路,代码看起来简洁潇洒大气木毛病,正嘚瑟着问题来了,对端一关闭傻眼了,新请求直接把attachment擦除了,所以还是别顺带了,老老实实给每个任务开个buffer吧。

        坑二,这些年搬砖一直追求精益求精对资源少占少用,C、C++一个套接字底层对应两块buffer,一读一写井水不犯河水相安无事,ByteBuffer对象是环形buffer,通过flip方法实现读写缓存的逆转,把position游标值和limit提交值一变轻松搞定,好是好但在线程池里维护一个连接上的各个buffer就够费劲的这还非要把读写合并一堆儿,真考验人呀,加锁呗,行是行就是显得low。

        坑三,把SelectionKey对象的实例作为线程入口参数派发,表面看没毛病,但在完成各个事件处理以后重新注册监听事件的时候线程间同步又成了问题,其实这个坑已经解答了上面的疑问,读写分离按需注册固然完美,但每个线程的执行时间是不同的,CPU时间片调度也只能相对均衡,保不齐谁早点谁晚点,一个close操作秒完,那边任务才跑一半,咔嚓一下就把注册的监听事件给改了,结果这边的注册失效了,傻了吧唧还等呢,左等不来右等不来结果下班了。

        坑四,SocketChannel对象关闭以后把SelectionKey实例的valid记做false,打标记倒是无所谓啦,不过无效的对象是不是就别再放在监听集合里处理是不是好点呀,免得每次还要判断,不判断就抛出一个异常,你看人家C库epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)设置EPOLL_CTL_DEL清理的干干净净,或许这么玩有人家自己的道理吧,相信别人这么做是有道理的。

        把接收缓存和频道对象作为入参传给线程池进行任务处理,保证每次请求都能被唯一的指派,强调服务的一对一特性,处理完流程内部直接返回了,能做成读写异步自然好呀,不过写这个框架是有私心的,业务指向十分明确,其他的需求还是另起炉灶或许更好一些。最后还是要强调一下,不同的业务对通信方式的要求不尽相同,所以一个框架解决不了所有问题,还是应该具体问题具体分析。

        难得一本正经的写个东西浅显地剖析一个不是问题的问题,口号喊起来:励斌出品,必是精品,欧耶!

相关文章
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
2天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
25天前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
23 2
|
2月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
76 2
|
3月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
108 0
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
156 1
|
3月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
64 0
|
4月前
|
安全 Java
【Java】已解决java.nio.channels.OverlappingFileLockException异常
【Java】已解决java.nio.channels.OverlappingFileLockException异常
112 1
|
4月前
|
Java
【Java】已解决java.nio.channels.ClosedChannelException异常
【Java】已解决java.nio.channels.ClosedChannelException异常
358 1