簡體   English   中英

如何在Java / Scala中中斷提交給newSingleThreadExecutor的線程?

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

鑒於我有以下測試代碼:

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秒。 如果超過時間限制,則應立即中斷相應的線程。 為了中斷該線程,我在捕獲TimeoutException時嘗試了兩種方法:

f.cancel(true)

service.shutdownNow()

但是,根據我的測試,上述方法無法中斷線程。

所以我想知道是否有一種方法可以強制中斷線程。

在此處輸入圖片說明

根據針對Future#cancelExecutorService#shutdownNow JavaDocs的說法,典型的實現是這些方法導致中斷基礎線程。

如果任務已經開始,則mayInterruptIfRunning參數確定是否應中斷執行該任務的線程以嘗試停止該任務。

除了盡最大努力嘗試停止處理正在執行的任務之外,沒有任何保證。 例如,典型的實現將通過Thread.interrupt()取消,因此任何無法響應中斷的任務都可能永遠不會終止。

特別注意最后一條評論。 通過Thread#interrupt方法進行的Thread#interrupt是一個協作過程。 當一個線程中斷另一個線程時,將導致設置目標線程的中斷狀態。 另外,如果目標線程被某些特定方法阻塞,則該線程將遇到InterruptedException

如果在目標線程中執行的代碼既不通過Thread#isInterrupted方法定期檢查中斷狀態,也不調用阻塞方法並處理InterruptedException ,則中斷實際上不會執行任何操作。 該代碼在中斷過程中不起作用,因此盡管有線程中斷,實際上也沒有辦法將其關閉。

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

理想情況下,應更改打算在后台線程中執行的長時間運行的代碼以配合線程中斷。 在您的示例中,一種可行的技術是在for循環的每N次迭代中更改sum以檢查Thread#isInterrupted ,如果被中斷,則中止循環。 然后,它可能會拋出異常以指示它尚未完成,或者可能返回一些前哨BigInt值以指示中止。

如果確實不能更改被調用的代碼,那么您將無法通過線程中斷將其暫停。 您可能會使用守護程序線程,以便至少這些線程在關閉期間不會阻止JVM退出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM