鉴于我有以下测试代码:
import java.util.concurrent._
object TestTime {
def main(args: Array[String]) {
println("starting....")
val service = Executors.newSingleThreadExecutor
val r = new Callable[Unit]() {
override def call(): Unit = {
//your task
val t0 = System.nanoTime
val total = sum(1000000000)
val t1 = System.nanoTime
println("Elapsed time " + (t1 - t0) / 1e9 + " secs")
println(s"total = $total")
}
}
val f = service.submit(r)
try {
// attempt the task for 2 second
f.get(2, TimeUnit.SECONDS)
} catch {
case _: TimeoutException =>
f.cancel(true)
println(s"Timeout....")
} finally {
service.shutdown()
}
println("after 2 seconds....")
for(i <- 1 to 2){
println(s"$i ...")
Thread.sleep(1000)
}
println("main thread ends...")
}
//Given that sum() is written by others and I cannot change it.
def sum(k: Int): BigInt = {
var total: BigInt = 0
for (i <- 1 to k) {
total += i
}
total
}
}
我想最多执行sum
2秒。如果超过时间限制,应立即中断相应的线程。为了中断该线程,我在catch TimeoutException
时尝试了两种方法:
f.cancel(true)
service.shutdownNow()
但是,根据我的测试,上述方法无法中断线程。
所以我想知道是否存在强制中断线程的方法。
答案 0 :(得分:5)
根据Future#cancel
和ExecutorService#shutdownNow
的JavaDocs,典型的实现是这些方法导致中断底层线程。
如果任务已经启动,那么mayInterruptIfRunning参数确定执行此任务的线程是否应该在尝试停止任务时被中断。
除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。
特别注意最后的评论。通过Thread#interrupt
方法的线程中断是一个合作过程。当一个线程中断另一个线程时,它会导致设置目标线程的中断状态。此外,如果目标线程在某些特定方法中被阻止,那么该线程将遇到InterruptedException
。
如果目标线程中执行的代码既没有通过Thread#isInterrupted
方法定期检查中断状态,也没有调用阻塞方法并处理InterruptedException
,那么中断实际上什么都不做。该代码在中断过程中没有合作,因此尽管线程中断,实际上没有办法将其关闭。
//Given that sum() is written by others and I cannot change it.
理想情况下,用于在后台线程中执行的长时间运行的代码将被更改为在线程中断中协作。在您的示例中,一种可行的技术是在sum
循环的每N次迭代中更改Thread#isInterrupted
以检查for
,如果中断,则中止循环。然后,它可以抛出异常以指示它没有完成或可能返回一些标记BigInt
值以指示中止是否合适。
如果真正无法更改调用的代码,则无法通过线程中断将其停止。您可以使用daemon threads,这样至少这些线程在关闭期间不会阻止JVM退出。