2017-06-06 2 views
1

J'ai lu Guide Netty, il n'explique pas beaucoup sur ChannelFuture. Je suis confus pourquoi cela ne provoquera pas une impasse.Comment Netty ChannelFuture notifier ne provoque pas le verrouillage

1.Il m'apprend à démarrer un serveur comme celui-ci.

ServerBootstrap sb = new ServerBootstrap(); 
     sb.group(bossGroup, workerGroup); 
     sb.channel(NioServerSocketChannel.class); 
     sb.localAddress(new InetSocketAddress(port)); 
     sb.childHandler(new ChannelInitializer<SocketChannel>() { 

       @Override 
       public void initChannel(SocketChannel ch) throws Exception { 
         ch.pipeline().addLast(new BigGameMessageDecoder(msgRegistry)); 
         ch.pipeline().addLast(BIG_MSG_ENCODER); 
        if (isDebug) { 
         ch.pipeline().addLast(MSG_LOGGER); 
        } 

        ch.pipeline().addLast(new GameMessageHandler<>(msgRegistry, 
          sessionFactory.createGameSession(), event, false)); 
       } 

     }); 

     ChannelFuture cf = sb.bind().sync(); 
     logger.error("start server at port: {}", port); 
     if (sync) { 
      cf.channel().closeFuture().sync(); 
     } 

En ligne:

ChannelFuture cf = sb.bind().sync(); 

sb.bind() retourne un ChannelFuture et sync() attendra que ce futur isDone.

Je lis le code DefaultChannelGroupFuture, il me montre à sync() appelle await() en effet. Et await() se verrouiller, attendez que d'autres notifier.

Et dans la fonction ChannelFuturesetSuccess il essaie d'obtenir à nouveau ce verrou. Donc, ma question est si sync() obtient le verrou en premier, puis attend et ChannelFuture essaie de notifier, mais il ne peut pas obtenir le verrou. Cela va-t-il provoquer une impasse?

  1. Si non, comment ChannelFuture peut-il notifier d'autres écouteurs?

  2. D'autres livres me dit N'UTILISER sync() ou await() dans ChannelHandler car cela pourrait provoquer une impasse. Pourquoi? Quelle est la différence entre les questions 1 et 3?


public DefaultChannelGroupFuture sync() throws InterruptedException { 
    super.sync(); 
    return this; 
} 

    public Promise<V> sync() throws InterruptedException { 
    await(); 
    rethrowIfFailed(); 
    return this; 
} 


    public Promise<V> await() throws InterruptedException { 
    if (isDone()) { 
     return this; 
    } 

    if (Thread.interrupted()) { 
     throw new InterruptedException(toString()); 
    } 

    synchronized (this) { 
     while (!isDone()) { 
      checkDeadLock(); 
      incWaiters(); 
      try { 
       wait(); 
      } finally {`enter code here` 
       decWaiters(); 
      } 
     } 
    } 
    return this; 
} 

    public Promise<V> setSuccess(V result) { 
    if (setSuccess0(result)) { 
     notifyListeners(); 
     return this; 
    } 
    throw new IllegalStateException("complete already: " + this); 
} 



    private boolean setSuccess0(V result) { 
    if (isDone()) { 
     return false; 
    } 

    synchronized (this) { 
     // Allow only once. 
     if (isDone()) { 
      return false; 
     } 
     if (result == null) { 
      this.result = SUCCESS; 
     } else { 
      this.result = result; 
     } 
     if (hasWaiters()) { 
      notifyAll(); 
     } 
    } 
    return true; 
} 

Répondre

1

Dans votre code ci-dessus: sinon,

public Promise<V> await() throws InterruptedException { 
if (isDone()) { 
    return this; 
} 

if (Thread.interrupted()) { 
    throw new InterruptedException(toString()); 
} 

synchronized (this) { 
    while (!isDone()) { 
     checkDeadLock(); 
     incWaiters(); 
     try { 
      wait(); 
     } finally {`enter code here` 
      decWaiters(); 
     } 
    } 
} 
return this; 

Le code de la méthode synccheckDeadLock(); vérifieront thread courant n'est pas filet intérieur qui est utilisé pour traiter io événement, la l'interblocage se produira alors que l'opération de rattachement sera envoyée au même thread qui attendra le verrou. Et alors, le wait(); libérera le verrou de this et wai t pour un thread acquérir le verrou et le notifier.Quand le thread IO appeler le setSuccess, il peut acquérir le verrou, parce que personne ne détient le verrou.

+0

Donc si dans ma méthode channelHandler 'channelInactive' essayez de reconnecter la synchronisation comme ceci' bootstrap.connect(). Sync(); 'Le' bootstrap' est le strap pour connecter le serveur. Par notre conclusion ci-dessus, il va jeter une exception par certains. Mais en réalité, l'occurrence d'une exception est fortuite. 'io.netty.util.concurrent.BlockingOperationException: DefaultChannelPromise @ 3b72750a (incomplet) à l'adresse io.netty.util.concurrent.DefaultPromise.checkDeadLock (DefaultPromise.java:380) ~ [netty-all-4.0.13.Final. jar: 4.0.13.Final] à io.netty.channel.DefaultChannelPromise.checkDeadLock (DefaultChann' – wangcaicai

+0

@ user8119590 en raison de l'awai() pas attendre le verrou une fois l'opération terminée.vous pouvez exécuter le code 'bootstrap.connect() .channel(). closeFuture(). sync() ', et voir ce qu'il s'est passé – dabaicai

+0

Je l'ai compris, cela dépend si l'avenir de' bootstrap.connect() 'répondra rapidement ou non.) 'if' isDone() 'retourne la méthode' true' va retourner, donc il n'y a pas d'exception Et si 'isDone()' retourne 'false' alors la méthode va vérifier le blocage. @dabaicai – wangcaicai