4

I have codebase that calls a black box, that in turn calls other code I have control of, call it thing.innerMethod(). The code in the black box needs to execute in a different thread than the code that calls it, so I have decided to use an executor:

Future<String> bbFuture = executorService.submit(() -> {
  return blackBox.doStuff(thing);});

If the execution takes too long, the user might call another endpoint that ultimately calls bbFuture.cancel(), triggering a CancellationException in the thread with the future and an InterruptedException in the thread running inside the executor.

The problem is that when the InterruptedException propagates into the black box, it catches it and logs it a stack trace, and raises false alarms. I don't need to catch every InterruptedException, but I know a place I could put a catch that would get probably 90% of them. The problem is I don't really have a good way to stop execution without returning from the function, and any partial or dummy result would probably trigger another exception. I know I could use Thread.currentThread().stop(), but stop() is deprecated.

How can I stop execution inside a java executor without returning or throwing an exception?

Dan
  • 12,157
  • 12
  • 50
  • 84
  • 4
    There's no (sane) way for stopping a thread in Java without relying on cooperative mechanisms (i.e. flags, exceptions, ...). See also https://stackoverflow.com/a/671052/402428 – michid Oct 20 '22 at 06:19
  • @michid: I know, but I was hoping that there was a cooperative mechanism from *within* the thread that worked. That or something like "create process, get PID and SIGKILL" but with java interfaces instead of OS-specific ones. – Dan Oct 20 '22 at 23:17
  • Are you saying, `.doStuff` throws and logs an exception? If that's the case, there isn't anything you can do. – matt Nov 01 '22 at 22:24

1 Answers1

1
  1. You can choose to run the task user wants to cancel by wrapping the future into another object which implements cancel() request and do not delegate the user given cancel request to the underlying future instance. In this case, the task will run as normal. (Trick user that the task cancelled but run in background and do not care the result of the task -- If the task has side-effect, this might not be desirable) -- will use computing resources.

  2. If you want the task to be responsive to interruption, then you should use the regular way of cancelling a task, namely notify the task that it should no longer continue by future.cancel() and the task you are notifying should be coded in a way that detects interruptions and clears any state required and return. (return something like an empty result, a special result etc.)

NOTE: future.cancel() sets a specific boolean field in Thread class. Some blocking library functions throws InterruptedException in the entry before doing something. For instance, Thread.sleep function might look to see if the boolean flag is set and throw InterruptedException without waiting, or it might wait and somehow detect the cancellation request before waiting to the end and throw InterruptedException. Or it might not detect at all. In this case, you should check regulary through out the task that if the task cancelled. [ using Thread.currentThread().isInterrupted()]

Ahmet M
  • 71
  • 3