docs: @Override
      public void launch(@NonNull ThreadingModel threading) {
          this.threadingModel = threading;
  
          switch (threading) {
              case SINGLE_THREAD: {
  
                  log.warn("SINGLE_THREAD model is used, performance will be significantly reduced");
  
                  // single thread for all queues. shouldn't be used in real world
                  threadA = new Thread(() -> {
                      while (runner.get()) {
                          if (subscriptionForShards != null)
                              subscriptionForShards.poll(messageHandlerForShards, 512);
  
                          idler.idle(subscriptionForClients.poll(messageHandlerForClients, 512));
                      }
                  });
  
                  threadA.setDaemon(true);
                  threadA.start();
                  }
                  break;
              case DEDICATED_THREADS: {
                  // we start separate thread for each handler
  
                  /**
                   * We definitely might use less conditional code here, BUT i'll keep it as is,
                   * only because we want code to be obvious for people
                   */
                  final AtomicBoolean localRunner = new AtomicBoolean(false);
                  if (nodeRole == NodeRole.NONE) {
                      throw new ND4JIllegalStateException("No role is set for current node!");
                  } else if (nodeRole == NodeRole.SHARD || nodeRole == NodeRole.BACKUP || nodeRole == NodeRole.MASTER) {
                      // // Shard or Backup uses two subscriptions
  
                      // setting up thread for shard->client communication listener
                      if (messageHandlerForShards != null) {
                          threadB = new Thread(() -> {
                              while (runner.get())
                                  idler.idle(subscriptionForShards.poll(messageHandlerForShards, 512));
  
                          });
                          threadB.setDaemon(true);
                          threadB.setName("VoidParamServer subscription threadB [" + nodeRole + "]");
                      }
  
                      // setting up thread for inter-shard communication listener
                      threadA = new Thread(() -> {
                          localRunner.set(true);
                          while (runner.get())
                              idler.idle(subscriptionForClients.poll(messageHandlerForClients, 512));
                      });
  
                      if (threadB != null) {
                          Nd4j.getAffinityManager().attachThreadToDevice(threadB,
                                          Nd4j.getAffinityManager().getDeviceForCurrentThread());
                          threadB.setDaemon(true);
                          threadB.setName("VoidParamServer subscription threadB [" + nodeRole + "]");
                          threadB.start();
                      }
                  } else {
                      // setting up thread for shard->client communication listener
                      threadA = new Thread(() -> {
                          localRunner.set(true);
                          while (runner.get())
                              idler.idle(subscriptionForClients.poll(messageHandlerForClients, 512));
                      });
                  }
  
                  // all roles have threadA anyway
                  Nd4j.getAffinityManager().attachThreadToDevice(threadA,
                                  Nd4j.getAffinityManager().getDeviceForCurrentThread());
                  threadA.setDaemon(true);
                  threadA.setName("VoidParamServer subscription threadA [" + nodeRole + "]");
                  threadA.start();
  
                  while (!localRunner.get())
                      try {
                          Thread.sleep(50);
                      } catch (Exception e) {
                      }
              }
                  break;
              case SAME_THREAD: {
                  // no additional threads at all, we do poll within takeMessage loop
                  log.warn("SAME_THREAD model is used, performance will be dramatically reduced");
              }
                  break;
              default:
                  throw new IllegalStateException("Unknown thread model: [" + threading.toString() + "]");
          }
      }