/**
   * Asynchronously runs the Proton {@link Reactor} accepting and sending messages. Any other call
   * to this method on this {@link AmqpsIotHubConnection} will block until the {@link Reactor}
   * terminates and this {@link AmqpsIotHubConnection} closes. Normally, this method should only be
   * called once by the {@link #open()} method until the {@link AmqpsIotHubConnection} has been
   * closed.
   *
   * @throws IOException if the {@link AmqpsIotHubConnectionBaseHandler} has not been initialized.
   * @throws InterruptedException if there is a problem acquiring the semaphore.
   */
  private synchronized void startReactorAsync() throws IOException, InterruptedException {
    // Acquire permit to continue execution of this method and spawn a new thread.
    reactorSemaphore.acquire();

    if (this.amqpsHandler != null) {
      this.reactor = Proton.reactor(this);

      new Thread(
              () -> {
                try {
                  reactor.run();

                  // Closing here should be okay. The reactor will only stop running if the
                  // connection is remotely
                  // or locally closed. The transport will attempt to receive/send a message and
                  // will get an exception
                  // causing it to create a new AmqpsIoTHubConnection.
                  close();

                  // Release the semaphore and make permit available allowing for the next reactor
                  // thread to spawn.
                  reactorSemaphore.release();
                } catch (Exception e) {
                  close();
                  reactorSemaphore.release();
                }
              })
          .start();
    } else {
      throw new IOException(
          "The Handler has not been initialized. Ensure that the AmqpsIotHubConnection is in an OPEN state by calling open().");
    }
  }