channel.writeAndFlush写回不会立马执行

前景提示:在用netty进行websocket客户端、服务端消息传递时,发现服务端使用netty的channel.writeAndFlush不是立马写回,而是等待后面几条消息后一起返回的,出现"netty消息发送成功至客户端"日志扎堆出现;监听回调代码:

  channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(returnHuaWei))).addListener((ChannelFutureListener) future -> {
                        if (future.cause() != null) {
                            log.error("netty消息发送失败:", future.cause());
                        } else if (future.isSuccess()) {
                            log.info("netty消息发送成功至客户端 returnHuaWei:{}", JSON.toJSONString(StringUtil.jsonStringReplace(JSON.parseObject(JSON.toJSONString(returnHuaWei)), "audio", "")));
                        } else {
                            log.error("Message send failed for an unknown reason.");
                        }
                    });

原因:

该段代码的作用是根据当前线程是否在事件循环中,决定如何执行写操作:

  1. 如果该线程在事件循环线程中:直接执行写操作,并根据 flush 参数选择是否刷新数据。
  2. 如果该线程不在事件循环线程中:则将写操作封装为异步任务 (WriteTask),并将该任务提交到事件循环中执行。

flush 的值控制着数据是否需要立即刷新,而 promise 用于跟踪异步操作的状态。

这段代码是为了确保在高并发环境下(如网络通信中),写操作能够正确地提交和执行,同时保证线程安全和异步执行。


 

在 Netty 中,所有的网络操作(比如写数据、读数据)都是异步执行的。为了高效地处理大量的请求,Netty 将这些任务分配到专门的 事件循环线程 上执行。

当你发起一个网络操作时,Netty 会判断当前的操作是:

  • 在事件循环线程上执行:也就是说,当前的线程是负责处理网络任务的专用线程。这样可以直接在当前线程上执行网络操作。
  • 不在事件循环线程上执行:这意味着你可能是在其他线程(比如工作线程或主线程)上发起操作,这时就需要把任务交给事件循环线程来执行。

我在主线程中通过 countDownLatch.await(2, TimeUnit.MINUTES)等待消息发送完成,countDownLatch释放时机为onMeessage接收到最后一帧数据时,通过finally来处理关闭;这是不合理的,会导致主线程一直阻塞,主线程阻塞可能导致线程资源竞争 或 I/O 操作延迟,则可能间接影响事件循环线程的任务调度;

解决方案为右侧代码,连接之后用countDownLatch.await等待,但是在连接打开的onOpen方法里面释放,从而让主线程结束,到onMessage的任务线程时,接收到最后一帧消息后关闭连接,这样就不会导致主线程阻塞;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值