@Override
  public boolean add(Channel channel) {
    ConcurrentSet<Channel> set =
        channel instanceof ServerChannel ? serverChannels : nonServerChannels;

    boolean added = set.add(channel);
    if (added) {
      channel.closeFuture().addListener(remover);
    }

    if (stayClosed && closed) {

      // First add channel, than check if closed.
      // Seems inefficient at first, but this way a volatile
      // gives us enough synchronization to be thread-safe.
      //
      // If true: Close right away.
      // (Might be closed a second time by ChannelGroup.close(), but this is ok)
      //
      // If false: Channel will definitely be closed by the ChannelGroup.
      // (Because closed=true always happens-before ChannelGroup.close())
      //
      // See https://github.com/netty/netty/issues/4020
      channel.close();
    }

    return added;
  }
 @Override
 public boolean contains(Object o) {
   if (o instanceof Channel) {
     Channel c = (Channel) o;
     if (o instanceof ServerChannel) {
       return serverChannels.contains(c);
     } else {
       return nonServerChannels.contains(c);
     }
   } else {
     return false;
   }
 }
  @Override
  public boolean remove(Object o) {
    if (!(o instanceof Channel)) {
      return false;
    }
    boolean removed;
    Channel c = (Channel) o;
    if (c instanceof ServerChannel) {
      removed = serverChannels.remove(c);
    } else {
      removed = nonServerChannels.remove(c);
    }
    if (!removed) {
      return false;
    }

    c.closeFuture().removeListener(remover);
    return true;
  }
 @Override
 public Iterator<Channel> iterator() {
   return new CombinedIterator<Channel>(serverChannels.iterator(), nonServerChannels.iterator());
 }
 @Override
 public void clear() {
   nonServerChannels.clear();
   serverChannels.clear();
 }
 @Override
 public int size() {
   return nonServerChannels.size() + serverChannels.size();
 }
 @Override
 public boolean isEmpty() {
   return nonServerChannels.isEmpty() && serverChannels.isEmpty();
 }