【问题标题】:What causes BlockingOperationException in Netty 4?什么导致 Netty 4 中的 BlockingOperationException?
【发布时间】:2018-02-11 16:49:24
【问题描述】:

最近,我在我的 netty4 项目中找到了一些BlockingOperationException

有人说使用start netty的ServerBootstrap的sync()方法时会导致死锁,因为sync()会调用await()方法,而await()中有一个叫做'checkDeadLock'的方法。

但我不这么认为。 ServerBootstrap 使用名为 boosGroup 的 EventLoopGroup,Channel 使用 workerGroup 操作 IO,我认为它们不会相互影响,它们有不同的 EventExecutor。

而且在我的实践中,Netty启动过程中并没有出现Deadlock异常,大部分发生在await writeAndFlush的Channel之后。

分析源码,checkDeadLock,BlockingOperationException是当当前线程和executor线程相同时抛出的异常。

我的项目代码被炸了:

private void channelWrite(T message) {
    boolean success = true;
    boolean sent = true;
    int timeout = 60;
    try {
        ChannelFuture cf = cxt.write(message);
        cxt.flush();
        if (sent) {
            success = cf.await(timeout);
        }
        if (cf.isSuccess()) {
            logger.debug("send success.");
        }
        Throwable cause = cf.cause();
        if (cause != null) {
            this.fireError(new PushException(cause));
        }
    } catch (LostConnectException e) {
        this.fireError(new PushException(e));
    } catch (Exception e) {
        this.fireError(new PushException(e));
    } catch (Throwable e) {
        this.fireError(new PushException("Failed to send message“, e));
    }
    if (!success) {
        this.fireError(new PushException("Failed to send message"));
    }
}

我知道Netty官方建议不要使用sync()或者await()方法,但是我想知道什么情况会导致进程死锁,当前线程和执行线程是一样的。强>

我更改了我的项目代码。

private void pushMessage0(T message) {
    try {
        ChannelFuture cf = cxt.writeAndFlush(message);
        cf.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws PushException {
                if (future.isSuccess()) {
                    logger.debug("send success.");
                } else {
                    throw new PushException("Failed to send message.");
                }
                Throwable cause = future.cause();
                if (cause != null) {
                    throw new PushException(cause);
                }
            }
        });
    } catch (LostConnectException e) {
        this.fireError(new PushException(e));
    } catch (Exception e) {
        this.fireError(new PushException(e));
    } catch (Throwable e) {
        this.fireError(new PushException(e));
    }
}

但是我遇到了一个新问题,我无法从 ChannelHandlerListener 获取 pushException。

【问题讨论】:

  • 当然不能。你甚至还没来得及看它就扔了自己的东西。涉及future.cause() 的代码应该在前面的else 块内,而不是在里面。
  • 您的pushMessage 抛出pushexception 在异步世界中不起作用,它应该为操作返回一个Future,或者对状态使用回调

标签: java netty


【解决方案1】:

如果您在EventExecutor 正在使用且Future 绑定到的同一线程中在Future 上调用sync*await*,netty 将抛出BlockingOperationException。这通常是Channel 本身使用的EventLoop

【讨论】:

    【解决方案2】:

    在 IO 线程中不能调用 await 是可以理解的。但是,有 2 点。 1、如果你在channel handler中调用下面的代码,不会报异常,因为await中isDone的检查大部分时候返回true,因为你在IO线程,IO线程是同步写数据的。调用 await 时数据已写入。

    ChannelPromise p = ctx.writeAndFlush(msg);
    p.await()
    
    1. 如果在不同的 EventExecutorGroup 中添加处理程序,则无需进行此检查,因为该执行程序是新创建的,并且与通道的 IO 执行程序不同。

    【讨论】:

      猜你喜欢
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多