简体   繁体   English

如何在Java / Scala中中断提交给newSingleThreadExecutor的线程?

[英]How to interrupt a thread submitted to newSingleThreadExecutor in Java/Scala?

Given that I have the following test-code: 鉴于我有以下测试代码:

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

I would like to execute the sum at most 2 seconds. 我想执行sum最多为2秒。 If it exceeds the time limit, the corresponding thread should be interrupted immediately. 如果超过时间限制,则应立即中断相应的线程。 To interrupt that thread, I have tried two methods when catch TimeoutException : 为了中断该线程,我在捕获TimeoutException时尝试了两种方法:

f.cancel(true)

service.shutdownNow()

However, according to my test, the above methods cannot interrupt the thread. 但是,根据我的测试,上述方法无法中断线程。

So I would like to know is there method to interrupt a thread compulsively. 所以我想知道是否有一种方法可以强制中断线程。

在此处输入图片说明

According to JavaDocs for both Future#cancel and ExecutorService#shutdownNow , the typical implementation is that these methods result in interrupting the underlying thread. 根据针对Future#cancelExecutorService#shutdownNow JavaDocs的说法,典型的实现是这些方法导致中断基础线程。

If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task. 如果任务已经开始,则mayInterruptIfRunning参数确定是否应中断执行该任务的线程以尝试停止该任务。

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. 除了尽最大努力尝试停止处理正在执行的任务之外,没有任何保证。 For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate. 例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。

Note particuarly the last comment. 特别注意最后一条评论。 Thread interruption via the Thread#interrupt method is a cooperative process. 通过Thread#interrupt方法进行的Thread#interrupt是一个协作过程。 When one thread interrupts another, it results in setting the target thread's interrupted status. 当一个线程中断另一个线程时,将导致设置目标线程的中断状态。 Also, if the target thread is blocked in certain specific methods, then that thread will experience an InterruptedException . 另外,如果目标线程被某些特定方法阻塞,则该线程将遇到InterruptedException

If the code executing in the target thread neither checks for interrupted status periodically via the Thread#isInterrupted method nor calls a blocking method and handles InterruptedException , then interruption effectively does nothing. 如果在目标线程中执行的代码既不通过Thread#isInterrupted方法定期检查中断状态,也不调用阻塞方法并处理InterruptedException ,则中断实际上不会执行任何操作。 That code is not cooperating in the interruption process, so there is effectively no way to shut it down, despite thread interruption. 该代码在中断过程中不起作用,因此尽管有线程中断,实际上也没有办法将其关闭。

//Given that sum() is written by others and I cannot change it.

Ideally, long-running code intended for execution in background threads would be changed to cooperate in the thread interruption. 理想情况下,应更改打算在后台线程中执行的长时间运行的代码以配合线程中断。 In your example, a viable technique would be to change sum to check Thread#isInterrupted every N iterations of the for loop, and if interrupted, abort the loop. 在您的示例中,一种可行的技术是在for循环的每N次迭代中更改sum以检查Thread#isInterrupted ,如果被中断,则中止循环。 Then, it could either throw an exception to indicate that it didn't complete or possibly return some sentinel BigInt value to indicate the abort if that's appropriate. 然后,它可能会抛出异常以指示它尚未完成,或者可能返回一些前哨BigInt值以指示中止。

If the invoked code truly cannot be changed, then you cannot halt it by thread interruption. 如果确实不能更改被调用的代码,那么您将无法通过线程中断将其暂停。 You could potentially use daemon threads so that at least these threads won't block JVM exit during shutdown. 您可能会使用守护程序线程,以便至少这些线程在关闭期间不会阻止JVM退出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM