public void applyThreadFilter(@NotNull final DebugProcessImpl debugProcess, @Nullable LightOrRealThreadInfo filter) {
    final RequestManagerImpl requestManager = debugProcess.getRequestsManager();
    if (Comparing.equal(filter, requestManager.getFilterThread())) {
      // the filter already added
      return;
    }

    final ThreadReference oldFilterThread = requestManager.getFilterRealThread();
    final ThreadReference newFilterThread = filter == null ? null : filter.getRealThread();

    requestManager.setThreadFilter(filter);

    if (!DebuggerSession.filterBreakpointsDuringSteppingUsingDebuggerEngine()) {
      return;
    }

    EventRequestManager eventRequestManager = requestManager.getVMRequestManager();
    if (DebuggerUtilsAsync.isAsyncEnabled() && eventRequestManager instanceof EventRequestManagerImpl) {
      Stream<EventRequestManagerImpl.ThreadVisibleEventRequestImpl> requests =
        StreamEx.<EventRequest>of(eventRequestManager.breakpointRequests())
          .append(eventRequestManager.methodEntryRequests())
          .append(eventRequestManager.methodExitRequests())
          .select(EventRequestManagerImpl.ThreadVisibleEventRequestImpl.class);
      try {
        Stream<CompletableFuture> futures = requests
          .map(r -> newFilterThread != null ? r.addThreadFilterAsync(newFilterThread) : r.removeThreadFilterAsync(oldFilterThread));
        CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
      }
      catch (Exception e) {
        Throwable cause = DebuggerUtilsAsync.unwrap(e);
        if (cause instanceof VMDisconnectedException) {
          throw (VMDisconnectedException)cause;
        }
        LOG.error(new Exception(e));
      }
    }
    else if (newFilterThread == null || oldFilterThread != null) {
      final List<Breakpoint> breakpoints = getBreakpoints();
      for (Breakpoint breakpoint : breakpoints) {
        if (LineBreakpoint.CATEGORY.equals(breakpoint.getCategory()) || MethodBreakpoint.CATEGORY.equals(breakpoint.getCategory())) {
          requestManager.deleteRequest(breakpoint);
          breakpoint.createRequest(debugProcess);
        }
      }
    }
    else {
      // important! need to add filter to _existing_ requests, otherwise Requestor->Request mapping will be lost
      // and debugger trees will not be restored to original state
      if (eventRequestManager != null) {
        applyFilter(eventRequestManager.breakpointRequests(), request -> request.addThreadFilter(newFilterThread));
        applyFilter(eventRequestManager.methodEntryRequests(), request -> request.addThreadFilter(newFilterThread));
        applyFilter(eventRequestManager.methodExitRequests(), request -> request.addThreadFilter(newFilterThread));
      }
    }
  }
public void applyThreadFilter(@NotNull final DebugProcessImpl debugProcess, @Nullable LightOrRealThreadInfo filter)