我如何残酷地,无情地中止Java中的任务? [英] How can I brutally and mercilessly abort a task in Java?

查看:91
本文介绍了我如何残酷地,无情地中止Java中的任务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Java中编写了一个数独求解器作为家庭作业,我目前正在努力弄清楚它可能面临的有问题的输入,以使它更好。我已使用 David Bau的数独生成器生成了几千个数独网格,现在我正在对他们运行我的程序。

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.

问题是,虽然他们大多数在非常合理的时间完成,其中一些被证明是有问题的,并使我的算法搜索像疯了,直到我用完了堆空间。所以我想我应该离开解决工作到一个辅助线程,并运行它与超时。现在,我使用一个线程'pool'的一个线程(以 ExecutorService 的形式),我提交 Callable s。然后我尝试获取超时的值:

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);
}

我的问题是,显然, code> Future in Java 。 未来< T> .cancel(boolean)显然不会立即中断任务。正因为如此,池仍然带有一个未完成的任务,并且随后的尝试超时,因为他们从来没有机会运行。

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 我的算法是完全顺序的,不使用全局对象,并且不包含锁定。据我所知,如果任务随机取消,任何事情都不会出错;即使它是,它不是生产代码。

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.

推荐答案

我相信我的案子是特别的使用 Thread.stop ,所以这里是我的解决方案,人们相信他们的情况是足够的特别。 (我会非常小心,使用某处它实际上可能是重要的。)

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.)

正如大多数人指出的,没有干净的方式来停止任务,没有这个任务检查它是否应该停止。我创建了一个类,实现 Runnable 以这样的方式进行,如果它被杀死不会戏剧。结果字段( milliseconds )是 AtomicLong ,因为在正则 long 变量不保证是原子。

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 Runnable to carry out in such a way that it won't be dramatic if it's killed. The result field (milliseconds) is an AtomicLong because writes on regular long variables are not guaranteed to be atomic.

class SolveTimer implements Runnable
{
    private String buildData;
    private AtomicLong milliseconds = new AtomicLong(-1);

    public SolveTimer(String buildData)
    {
        assert buildData != null;
        this.buildData = buildData;
    }

    public void run()
    {
        long time = System.currentTimeMillis();
        // create the grid, solve the grid
        milliseconds.set(System.currentTimeMillis() - time);
    }

    public long getDuration() throws ContradictionException
    {
        return milliseconds.get();
    }
}

我的代码在每次迭代时创建一个线程, SolveTimer 。然后尝试在10秒内加入。 加入后,主线程调用 getDuration 运行定时器;

My code creates a thread on each iteration and runs a SolveTimer. It then attempts to join within 10 seconds. After join returns, the main thread calls getDuration on the run timer; if it returns -1, then the task is taking too long and the thread is killed.

SolveTimer timer = new SolveTimer(buildData);
Thread worker = new Thread(timer);
worker.start();
worker.join(10000);

long result = timer.getDuration();
if (result == -1)
{
    System.err.println("Unable to solve");
    worker.stop();
}

应该注意,这使得工作线程难以调试:当线程被调试器挂起,它仍然可以被 Thread.stop()杀死。在我的机器上,这会在控制台中写入一个关于 ThreadDeath 的简短错误消息,并导致Java进程崩溃。

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 about ThreadDeath in the console and crashes the Java process.

是可能的竞争条件,其中工作者线程完全(或紧接着) getDuration 被调用,因为即使任务实际成功,结果也将是 -1 。但是,这是我可以生活的东西:10秒已经太长了,所以在那一刻,我再也不在乎,如果接近够好。

There is a possible race condition where the worker thread completes exactly (or right after) getDuration is called, and because of that result will be -1 even 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.

这篇关于我如何残酷地,无情地中止Java中的任务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆