2016-04-11 3 views
1

В этом фрагменте кода shutdownGracefully(). SyncUninterruptibly() никогда не возвращается. Является ли это ожидаемым поведением или я что-то не понял? Испытано с Нетти 4.0.35.FinalShutdownGracefully() никогда не возвращает

public class ShutdownGracefullyDemo { 
    private ServerBootstrap bootstrap; 

    public static void main(String[] args) throws Exception { 
     new ShutdownGracefullyDemo().initialize(); 
    } 

    private void initialize() throws InterruptedException { 
     NioEventLoopGroup group = new NioEventLoopGroup(); 
     bootstrap = new ServerBootstrap(); 
     bootstrap.group(group) 
      .channel(NioServerSocketChannel.class) 
      .handler(new LoggingHandler(LogLevel.INFO)) 
      .childHandler(new MyInboundHandler()) 
      .bind(2025) 
      .sync() 
      .channel() 
      .closeFuture() 
      .sync(); 
    } 

    @ChannelHandler.Sharable 
    private class MyInboundHandler extends SimpleChannelInboundHandler<ByteBuf> { 
     Charset charset = Charset.forName("US-ASCII"); 

     @Override 
     protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) 
      throws Exception { 
      String data = msg.toString(charset); 
      System.out.println("Received: " + data); 
      if ("quit\r\n".equals(data)) { 
       shutdown(); 
      } 
     } 
    } 

    private void shutdown() { 
     if (bootstrap != null && bootstrap.group() != null) { 
      bootstrap.group().shutdownGracefully().syncUninterruptibly(); 
      System.out.println("shutdown completed"); 
     } 
    } 
} 

ответ

0

Вы можете выключение с помощью кода, как показано ниже:

public void shutdown() { 
    LOG.info("Gracefully shutdown http server ..."); 
    bossGroup.shutdownGracefully(2, 2, TimeUnit.SECONDS); 
    workerGroup.shutdownGracefully(2, 2, TimeUnit.SECONDS); 
} 

Метод "syncUninterruptibly()" исходный код на классе «io.netty.util.concurrent .DefaultPromise ":

@Override 
public Promise<V> awaitUninterruptibly() { 
    if (isDone()) { 
     return this; 
    } 

    boolean interrupted = false; 
    synchronized (this) { 
     while (!isDone()) { 
      checkDeadLock(); 
      incWaiters(); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       // Interrupted while waiting. 
       interrupted = true; 
      } finally { 
       decWaiters(); 
      } 
     } 
    } 

    if (interrupted) { 
     Thread.currentThread().interrupt(); 
    } 

    return this; 
} 

Задача заблокирован по методу ожидания(), он никогда не будет продолжаться до тех пор, пока уведомит(), так что приложение не может выключение завершена.

+0

Спасибо Derek за ваш ответ! В моем отрывке я вдохнул вдохновение из книги Нормана Маурера «Нетти в действии», где в примере завершения метод 'future.syncUninterruptibly()' вызывается после 'shutdownGracefully()' и фактически ложная логика вызова выключения и уведомления, когда завершение работы имеет смысл для меня. Но по какой-то причине это сбивает меня с толку, это не работает так, как ожидалось, поскольку никто не уведомляет ожидающую нить. – staedler

+0

Может быть сервер, ожидающий закрытия всего клиентского канала, и выполнение задачи на этом канале, например, мертвая блокировка, чтобы вы могли создать новый поток для выключения (или другого лучшего способа). –

1

Проблема в том, что вы создаете тупик.

Вы вызываете shutdownGracefully из потока внутри текущего цикла событий, это заставит его запланировать выключение, а затем дождитесь завершения каждого потока, прежде чем продолжить. Каждый поток не будет завершен, потому что вы ждете, пока цикл не завершится, и фактически создаст тупик.

В большом приложении, существует несколько способов, чтобы решить эту проблему:

Использование мастер резьбы:

это решает, имея глобальное применение основного потока, который вызывает метод выключения.

Добавление слушателя к изящным остановки:

Вместо:

.shutdownGracefully().syncUninterruptibly(); 
System.out.println("shutdown completed"); 

делают

shutdownGracefully().addListener(e -> {System.out.println("shutdown completed");}) 

В том, что это позволяет разматывать стек от способа отключения и правильно закройте эту резьбу

+0

Спасибо @Ferrybig, теперь я получил его. Что касается вашего последнего совета, не следует закрывать? Осторожно заботиться о закрытии всех каналов? По крайней мере, это то, что я понимаю, читая документацию netty: [link] (http://netty.io/wiki/user-guide-for-4.x.html#shutting-down-your-application) "... Он возвращает Будущее, которое уведомляет вас, когда EventLoopGroup полностью завершено, и все Каналы, принадлежащие к группе, были закрыты » – staedler

+0

@staedler. Вы действительно правы в последнем пункте, netty отключает каналы, отключая дочерние записи исполнителя – Ferrybig

Смежные вопросы