I programmed a sudoku solver in Java for a homework, and I am currently trying to figure out the problematic inputs it can face to make it better. I have generated a few thousand sudoku grids with David Bau’s sudoku generator, and now I am running my program against them.
The problem is that while most of them complete in very reasonable times, some of them prove to be problematic and make my algorithm search like crazy until I run out of heap space. So I thought I should offshore the solving job to a secondary thread and run it with a timeout. Right now, I’m using a thread ‘pool’ of one thread (in the form of an ExecutorService) and I’m submitting Callables to it. I then try to get the value with a timeout:
Callable<Long> solveAndReturnTime = new Callable<Long>() { /* snip */ };
Future<Long> time = executor.submit(solveAndReturnTime);
try
{
long result = time.get(10, TimeUnit.SECONDS);
System.out.printf("%d millis\n", result);
}
catch (TimeoutException e)
{
System.err.println("timed out");
time.cancel(true);
}
My problem is that apparently, one does not simply cancel a Future in Java. Future<T>.cancel(boolean) apparently doesn’t interrupt the task right away. Because of that, the pool is stuck with carrying an undying task, and the subsequent attempts timeout because they never get a chance to run.
Adding more threads to the pool is not an option because I run on limited cores and if too many tasks obstinately run, the legitimate ones will be unfairly slowed down. I also don’t want the overhead of frequently checking if the task was aborted from my main algorithm.
How can I abruptly, mercilessly and brutally terminate a task? I’m open to anything that will let me recover on the main thread.
EDIT My algorithm is completely sequential, uses no global object, and contains no lock. As far as I can tell, nothing will go wrong if the task is cancelled at a random moment; and even if it does, it’s not production code. I’m ready to walk the dangerous and treacherous walk for this one.
I believe my case was ‘special’ enough to use
Thread.stop, so here is my solution to the people who believe their case is special enough too. (I would take extreme care using that somewhere it could actually matter, though.)As mostly everyone points out, there’s no clean way to stop a task without having that task check if it should stop itself. I created a class that implements
Runnableto carry out in such a way that it won’t be dramatic if it’s killed. The result field (milliseconds) is anAtomicLongbecause writes on regularlongvariables are not guaranteed to be atomic.My code creates a thread on each iteration and runs a
SolveTimer. It then attempts to join within 10 seconds. Afterjoinreturns, the main thread callsgetDurationon the run timer; if it returns -1, then the task is taking too long and the thread is killed.It should be noted that this makes worker threads harder to debug: when the thread is suspended by the debugger, it can still be killed by
Thread.stop(). On my machine, this writes a short error message aboutThreadDeathin the console and crashes the Java process.There is a possible race condition where the worker thread completes exactly (or right after)
getDurationis called, and because of thatresultwill be-1even if the task actually succeeded. However, that’s something I can live with: 10 seconds is already far too long, so at that point I don’t really care anymore if it’s nearly good enough.