Java 以智能方式使计算线程可取消

Java 以智能方式使计算线程可取消,java,multithreading,performance,Java,Multithreading,Performance,我想知道如何在快速取消响应和线程性能之间达成折衷,我的线程体与此循环类似: for(int i=0; i<HUGE_NUMBER; ++i) { //some easy computation like adding numbers //which are result of previous iteration of this loop } 可能会降低代码的执行速度 即使我将上述条件更改为: if (i % 100 && Thread.currentTh

我想知道如何在快速取消响应和线程性能之间达成折衷,我的线程体与此循环类似:

for(int i=0; i<HUGE_NUMBER; ++i) {
    //some easy computation like adding numbers
    //which are result of previous iteration of this loop
}
可能会降低代码的执行速度

即使我将上述条件更改为:

if (i % 100 && Thread.currentThread().isInterrupted()) {
    throw new InterruptedException("Cancelled");            
}
然后,编译器不能只预先计算
i
的值,并且只在某些特定情况下检查条件,因为
巨数
是可变的,可以有不同的值

因此,我想问一下,是否有任何聪明的方法将此类检查添加到呈现的代码中,并且知道:

  • 大数值
    是可变的,可以有不同的值
  • 循环体由一些易于计算的代码组成,但依赖于以前的计算代码

我想说的是循环的一次迭代相当快,但是大量的迭代可能需要更多的时间,这就是我想要避免的。

让你的计算成为一个
迭代器

虽然这听起来不是非常有用,但这里的好处是,您可以非常轻松地编写过滤器迭代器,其灵活性令人惊讶。可以简单地添加和删除它们,即使是通过配置也可以。有很多好处——试试看

然后,您可以添加一个过滤
迭代器
,该迭代器定期监视时间并检查中断,或者更灵活的方法


您甚至可以在不影响原始计算的情况下添加进一步的筛选,方法是在原始计算中插入脆弱的状态检查。

首先,在这种情况下,使用
Thread.interrupted()
而不是
Thread.currentThread().isInterrupted()

您应该考虑一下,检查中断标志是否真的太慢了您的计算!一方面,如果循环体非常简单,即使大量迭代(上限为Integer.MAX_值)也会在几秒钟内运行。即使检查中断标志将导致20%或30%的开销,这也不会给算法的总运行时间增加太多

另一方面,如果循环体不是那么简单,因此它将运行更长的时间,那么测试中断标志将不会是一个显著的开销

不要做像if(i%10000==0)
这样的把戏,因为这会比一个“短”的
线程更慢地计算。interrupted()

您可以使用一个小技巧,但要三思而后行,因为它会使代码更复杂,可读性更低:

每当你有这样一个循环:

for (int i = 0; i < max; i++) {
    // loop-body using i
}
现在,您可以在内部循环之前或之后添加中断检查


我已经使用以下循环体在我的系统(JDK 7)上做了一些测试

if (i % 2 == 0) x++;
Integer.MAX_值/2
迭代次数。结果如下(预热后):

  • 无任何中断检查的简单循环:1949 ms
  • 每次迭代检查的简单循环:2219 ms(+14%)
  • 使用模:3166 ms(+62%)的简单循环,每100万次迭代检查一次
  • 使用位掩码每100万次迭代检查一次的简单循环:2653 ms(+36%)
  • 如上所述,带有检入外环路的间隔环路:1972 ms(+1.1%)

因此,即使循环体像上面一样简单,每次迭代检查的开销也只有14%!因此,建议不要使用任何技巧,只需在每次迭代中通过
Thread.interrupted()
检查中断标志即可

你说“编译器不能只在某些特定情况下预计算i值并检查条件”是什么意思?老实说,我并不知道将代码交给编译器后可能出现的所有性能调整。我只知道,若循环被设置为在常量上迭代,那个么它可能是简单的扩展(内联的)。由于
maging\u NUMBER
是一个变量,它不能简单地假设它的值并执行优化(可能JIT可以-但这是我的问题的一部分-如果JIT可以优化此代码,那么在每个循环迭代中添加检查并不会降低它的速度)。为什么不等到确定这是一个性能瓶颈。我怀疑检查线程中断状态是否需要很长时间。我不认为JIT的内联依赖于静态定义的循环周期。此外,您可以考虑使用<代码>线程。因为
isInterrupted()
不会重置状态。@EdwinDalorzo我从来没有说过JIT的内联依赖于静态定义的循环周期。这也不是一个实际的问题——当我有问题并把它写在这里以获得解决问题的帮助时。这显然是一个理论问题。使用
Thread.interruped()
会让我遇到同样的情况,我必须检查它是否返回true或false-并不总是需要清除线程状态。我只是想知道我是否可以避免在每次循环迭代中调用
if
中的外部方法。谢谢,这是一种非常有趣的方法-你在代码中尝试过吗?@MaciejDobrowolski-是的,我尝试过很多次-将循环转化为
迭代器所需的规则
教给你比你预期更多的关于你正在实现的算法的知识。
Thread.currentThread().isInterrupted()
清除线程中断状态不一定是我想要的。顺便说一句,把计算分成几个循环的聪明方法:)Thx。在这种情况下,清除interruption标志正是您想要的,因为您正在抛出InterruptionException!通常是这样做的:要么设置中断标志,要么抛出InterruptionException。另请参阅(阅读最后一行!)感谢您的计时。我现在可以删除我的答案了@isnot2bad感谢您给出测试结果!提高系统的复杂性可能真的毫无意义
int start = 0;
while (start < max) {       
    final int next = Math.min(start + INTERVAL_SIZE, max);
    for(int i = start; i < next; i++) {
        // loop-body using i
    }
    start = next;
}
if (i % 2 == 0) x++;