记一次JavaNIO重复读消费
在一次服务器端接收客户端发送的消息时,服务器端一直触发读就绪事件,导致服务端代码出现死循环,代码如下
客户端
public class Client1 {public static void main(String[] args) throws IOException, InterruptedException {SocketChannel socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);InetSocketAddress localhost = new InetSocketAddress("localhost", 8888);socketChannel.connect(localhost);while (!socketChannel.isConnected()) {socketChannel.finishConnect();}socketChannel.write(ByteBuffer.wrap("客户端数据".getBytes()));}
}
服务端
public class Server1 {public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();InetSocketAddress inetSocketAddress = new InetSocketAddress(8888);serverSocketChannel.bind(inetSocketAddress);serverSocketChannel.configureBlocking(false);Selector selector = Selector.open();serverSocketChannel.register(selector, 16);while (true) {int select = selector.select();System.out.println("当前有" + select + "个操作就绪");Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while (iterator.hasNext()) {SelectionKey next = iterator.next();if (next.isAcceptable()) {System.out.println("accept就绪++++++++++++++");ServerSocketChannel server = (ServerSocketChannel) next.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} else if (next.isReadable()) {System.out.println("读就绪+++++++++++++++++");ByteBuffer allocate = ByteBuffer.allocate(10240000);StringBuffer stringBuffer = new StringBuffer();SocketChannel channel = (SocketChannel) next.channel();int read = channel.read(allocate);while (read > 0) {allocate.flip();stringBuffer.append(new String(allocate.array(), 0, read));allocate.clear();read = channel.read(allocate);}System.out.println(stringBuffer);}}iterator.remove();}}
}
执行结果
最后在一个帖子里看到了答案https://segmentfault.com/q/1010000019694209
原因
- 如果客户端的socket断开连接后,会一直向服务端发送一个读就绪,即channel.read(allocate)=-1,这个时候服务端应该断开这个连接,或者至少注销掉OP_READ。
验证
- 在客户端的代码最后加一个线程睡眠,
Thread.sleep(1000000L);
可以看到,在客户端代码执行结束之前,服务端不会收到这个读就绪事件
解决
服务器端代码加上判断
public class Server1 {public static void main(String[] args) throws IOException {ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();InetSocketAddress inetSocketAddress = new InetSocketAddress(8888);serverSocketChannel.bind(inetSocketAddress);serverSocketChannel.configureBlocking(false);Selector selector = Selector.open();serverSocketChannel.register(selector, 16);while (true) {int select = selector.select();System.out.println("当前有" + select + "个操作就绪");Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> iterator = keys.iterator();while (iterator.hasNext()) {SelectionKey next = iterator.next();if (next.isAcceptable()) {System.out.println("accept就绪++++++++++++++");ServerSocketChannel server = (ServerSocketChannel) next.channel();SocketChannel socketChannel = server.accept();socketChannel.configureBlocking(false);socketChannel.register(selector, SelectionKey.OP_READ);} else if (next.isReadable()) {System.out.println("读就绪+++++++++++++++++");ByteBuffer allocate = ByteBuffer.allocate(10240000);StringBuffer stringBuffer = new StringBuffer();SocketChannel channel = (SocketChannel) next.channel();int read = channel.read(allocate);while (read > 0) {allocate.flip();stringBuffer.append(new String(allocate.array(), 0, read));allocate.clear();read = channel.read(allocate);}System.out.println(stringBuffer);// socket已经断开if (read == -1) {//增加注销操作// int readyOps = next.readyOps();//&~xx 代表取消事件,取反 按位与// next.interestOps(next.interestOps() & ~readyOps);// 或者断开服务端的这个socketchannel.close();}}}iterator.remove();}}
}
记一次JavaNIO重复读消费相关推荐
- 可重复读:为什么你改了我看不到呢?
在探索问题之前,先得明白如下知识点 InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id.它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的 ...
- 数据库事务隔离级别-- 脏读、幻读、不可重复读(清晰解释)
一.数据库事务隔离级别 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted .Read committed .Repeatable read .Serializable ,这四 ...
- 数据库零碎要点001_数据库的4大特性(原子性_持久性_隔离性_一致性)_数据库的隔离级别(脏读_幻读_不可重复读)_mysql如何设置隔离级别
本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务 ...
- MySQL 乱七八糟的可重复读隔离级别实现
点击上方"芋道源码",选择"置顶公众号" 技术文章第一时间送达! 源码精品专栏 精尽 Dubbo 原理与源码专栏( 已经完成 69+ 篇,预计总共 75+ 篇 ...
- MySQL的事务总结(事务特性,隔离级别,脏读,不可重复读,幻读,常见问题)
MySQL的事务总结(事务四大特性,隔离级别,脏读,幻读) MYSQL官网:https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-iso ...
- mysql不可重复读和重复读_MySql隔离级别:RU / RC / RR / S + 脏读 / 不可重复读 / 幻读 / 可重复读...
MySQL 事务 本文所说的 MySQL 事务都是指在 InnoDB 引擎下,MyISAM 引擎是不支持事务的. 数据库事务指的是一组数据操作,事务内的操作要么就是全部成功,要么就是全部失败,什么都不 ...
- mysql的读已提交和可重复读(Read Committed和Repeatable Read隔离级别)
1.共享锁和排他锁 1.1.共享锁 1.2.排他锁 1.3.总述 2.MVCC 2.1.隐藏字段 2.2.Read View 2.3.Undo log 2.4.update的具体流程 2.5.可见性比 ...
- MySQL可重复读和读已提交实现原理,深入理解MVCC。
1.隔离级别 MySQL中隔离级别分为4种,提未交读.读已提交.可重复读.串行化.同时MySQL默认隔离级别为可重复读. 图片 查看MySQL隔离级别 SELECT @@tx_isolation 设置 ...
- 快速理解脏读、不可重复读、幻读和MVCC
理解这三种由于并发访问导致的数据读取问题,再理解事务隔离级别就简单多了. 脏读(读取未提交数据) A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据 ...
最新文章
- java越权发送邮件_水平越权的常见解决方法
- 清理Mac上的软件容易吗?
- 在VS中建立一个易于管理的C++工程
- 【数据库系统概论】考研第六部分重点分析【6.1】
- jQuery中DOM操作方法 之 html,text,val
- 搜狐视频怎么更改头像
- JSON(5)---JSON.stringify()
- python生成器_Python生成器
- USBCNC输出板与VFD和主轴的使用
- 计算机怎么退出远程桌面连接,怎么退出远程桌面控制?远程桌面软件哪个好?
- 备战数学建模22-数学建模论文写作规范总结
- kettle 提交数据量_kettle大数据量读写mysql性能优化
- 如何解决浏览器未安装FLASH控件的提示
- 传奇服务端如何添加地图
- 泰克MDO3104示波器_六合一示波器_无限多功能
- 可变悬挂调节软硬_大众cc可变悬架软硬调节是什么意思
- 视频教程-数据库SQL查询,最佳案例讲解-SQL Server
- 定时任务一(quartz):纯java
- alexa是什么_Alexa的简要模式是什么?如何打开(或关闭)它?
- [小工具] chrome上日语翻译工具