killing a java thread in test

2019-09-06 19:36发布

问题:

I'm writing a sort of tutorial about programming (it will be a Java repo on github) where users can clone the repo and write their own code inside empty methods to solve algorithmic problems. After they write their code, they can launch unit tests to check if their solution is correct and if it completes execution in less than a certain time (to assure they found the most efficient solution). So my repo will contain a lot of classes with empty methods and all the non-empty unit tests to check the code the users will write.

What I'm doing in the JUnit tests is something like that:

// Problem.solveProblem() can be a long running task
Thread runner = new Thread(() -> Problem.solveProblem(input)); 

runner.start();

try {
    Thread.currentThread().sleep(500);
}
catch (InterruptedException e) {
    e.printStackTrace();
}

if (runner.isAlive()) {
    fail("Your algorithm is taking too long.");
    runner.stop();
}

Now, if a user writes a not optimized algorithm, the test fails correctly, but the runner thread will continue to run (and so will do the test thread) until it terminates, which can happen after minutes, though I call running.stop(). So I have tests that can last minutes instead of seconds like I'd like.

I know how to gracefully kill a thread in Java, but in this case I don't want the users to take care of multithreading issues (like checking/updating shared variables): I just want them to write only the code to solve the problem.

So my question is: is there a way to abruptly kill a thread in Java? If not, is there any other approach I could follow to accomplish my goal?

Thanks, Andrea

回答1:

Use Thread.currentThread().getThreadGroup() to iterate through. Thread.stop is the brute-force way, but in your case it'll probably work if you call Thread.interrupt -edit- I read this too quickly and thought you were calling sleep in your spawned threads. Rereading, I see that you are just doing this in your main thread, so as RealSkeptic commented on this post it is uncertain and probably unlikely that interrupt will solve the problem



回答2:

You can use a ScheduledExecutorService with a timeout:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); 
Future<?> future = executor.schedule(() -> Problem.solveProblem(input));
try {
    future.get(500, TimeUnit.MILLISECONDS);
} catch (Exception e){
    fail("Your algorithm is taking too long.");
    future.cancel(true);
}

Will probably require some refinements but you get the basics.