2017-09-03 5 views
2

최근에 netty4 프로젝트에서 BlockingOperationException이 발견되었습니다.Netty 4에서 BlockingOperationException의 원인은 무엇입니까?

startten netty의 ServerBootstrap의 sync() 메소드를 사용하면 sync()가 await() 메소드를 호출하고 await()에 'checkDeadLock'이라는 메소드가 있기 때문에 deadlock이 발생할 수 있다고합니다.

하지만 그렇게 생각하지 않습니다. ServerBootstrap은 boosGroup이라는 EventLoopGroup을 사용하고 Channel은 작업 IO를 위해 workerGroup을 사용합니다. 서로 영향을 미치지 않을 것이라고 생각합니다. 서로 다른 EventExecutor를가집니다.

내 연습에서는 데드락 예외가 Netty 시작 프로세스에 나타나지 않습니다. 대부분의 경우 writeAndFlush를 기다리는 채널 이후에 발생합니다.

분석 소스 코드, checkDeadLock, BlockingOperationException 현재 스레드와 실행 프로그램 실행 스레드가 동일한 경우 예외가 발생합니다. 내가의 Netty 관계자는 동기화()를 사용하지 않도록 조언 또는() 메소드를 기다리고 알고

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")); 
    } 
} 

하지만 나는 윌 과정과 현재의 교착 상태의 원인을 상황을 알고 싶어 :

내 프로젝트 코드는 타격 쓰래드와 Executor 실행 스레드는 동일합니다.

프로젝트 코드가 변경되었습니다.

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을 얻을 수 없습니다.

+0

물론 할 수는 없습니다. 당신은 심지어 당신이 그것을 보게되기 전에 당신 자신의 것을 던지고 있습니다. 'future.cause()'를 포함한 코드는 그곳에있는 것 대신에 이전의'else' 블록 안에 있어야합니다. – EJP

+0

'pushexception'을 던지는'pushMessage'는 비동기 세계에서 작동하지 않습니다. 작동을 위해 Future를 반환하거나, 상태를 위해 콜백을 사용해야합니다. – Ferrybig

답변

2

BlockingOperationException 당신이 EventExecutor 사용되며, 이는 Future가에 연결되는 것과 같은 스레드에 Futuresync* 또는 await*를 호출하는 경우 그물코에 의해 슬로우됩니다. 일반적으로 Channel에서 사용하는 EventLoop입니다.