docs: public synchronized void stop() {
          if (isRunning()) {
              VirtualCdj.getInstance().removeUpdateListener(updateListener);
              running.set(false);
              pendingUpdates.clear();
              queueHandler.interrupt();
              queueHandler = null;
  
              // Report the loss of our hot cached metadata on the proper thread, outside our lock
              final Set<DeckReference> dyingCache = new HashSet<DeckReference>(hotCache.keySet());
              SwingUtilities.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      for (DeckReference deck : dyingCache) {
                          if (deck.hotCue == 0) {
                              deliverTrackMetadataUpdate(deck.player, null);
                          }
                      }
  
                  }
              });
              hotCache.clear();
              deliverLifecycleAnnouncement(logger, false);
          }
      }