code: public AddressResolver<T> getResolver(final EventExecutor executor) {
          if (executor == null) {
              throw new NullPointerException("executor");
          }
  
          if (executor.isShuttingDown()) {
              throw new IllegalStateException("executor not accepting a task");
          }
  
          AddressResolver<T> r;
          synchronized (resolvers) {
              r = resolvers.get(executor);
              if (r == null) {
                  final AddressResolver<T> newResolver;
                  try {
                      newResolver = newResolver(executor);
                  } catch (Exception e) {
                      throw new IllegalStateException("failed to create a new resolver", e);
                  }
  
                  resolvers.put(executor, newResolver);
                  executor.terminationFuture().addListener(new FutureListener<Object>() {
                      @Override
                      public void operationComplete(Future<Object> future) throws Exception {
                          synchronized (resolvers) {
                              resolvers.remove(executor);
                          }
                          newResolver.close();
                      }
                  });
  
                  r = newResolver;
              }
          }
  
          return r;
      }
docs: Returns the {@link AddressResolver} associated with the specified {@link EventExecutor}. If there's no associated
  resolved found, this method creates and returns a new resolver instance created by
  {@link #newResolver(EventExecutor)} so that the new resolver is reused on another
  {@link #getResolver(EventExecutor)} call with the same {@link EventExecutor}.