熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java 基本功之中斷線程的理解

2022-06-13   來源: Java高級技術 

  設想這樣的情景我們的應用在某一個時間段內需要一個子線程不停的在後台運行這可能是一個下載過程是一個對服務端socket的監聽也可能是一個繪圖的計算過程當我們想要終止線程的時候我們會怎樣做呢?是設定一個標志變量來控制跳出循環?還是使用threadstop()?又或者是設置thread = null?

  有的時候我們需要一種規范的思路使用規范的方法來解決一類問題

  我們首先要明白線程終止的條件有三種情況

  當線程的run方法執行方法體中最後一條語句後

  當執行retutrn語句返回時

  當出現了在方法中沒有捕獲的異常時

  在Java的早期版本中還有一個stop方法其他線程可以調用它終止線程但是這個方法已經被棄用了所以還在用的同學就不要繼續用了

  我們的正確思路是使用interrupt方法來終止我們的線程

  首先要理解interrupt方法做了什麼每一個線程都有一個中斷狀態這是一個boolean標志當線程調用了interrupt方法時這個中斷狀態就會被置位如果我們要檢查中斷狀態可以使用ThreadcurrentThread()isInterrupted()來獲得是否中斷

  但是如果線程被阻塞了(sleep or wait)當我們調用了interrupt方法的時候就會產生InterruptedException異常這是我們可以利用的地方

  同樣的如果中斷狀態先被置位了然後我們調用了sleep方法線程不會休眠相反它將清除中斷狀態然後拋出InterruptedException

  我們調用了interrupt並不意味著線程會終止線程是否會終止以及會如何繼續是程序員來控制的

  在本文中我們將會討論終止線程的規范用法然後在一個例子中實際應用在這個例子中我們模擬了文件拷貝和游戲繪圖兩種情形做出的效果如下圖所示點擊start後上方進度條會顯示文件拷貝的進度點擊end則會停止拷貝點擊draw會在畫面中不停繪制各種各樣的矩形點擊stop則會停止繪制

  首先我們來看兩種情形的後台線程寫法

  public void run() {

  try{

  …

  while(!ThreadcurrentThreadisInterrupted() && more work to do)

  {

  do more work

  }

  }

  catch(InterruptedException)

  {

  //thread was interrupted during sleep or wait

  }

  finally

  {

  cleanup if required

  }

  //exiting the run method terminates the thread }

  public void run() {

  try{

  …

  while( more work to do)

  {

  do more work

  Threadsleep(delay)

  }

  }

  catch(InterruptedException)

  {

  //thread was interrupted during sleep or wait

  }

  finally

  {

  cleanup if required

  }

  //exiting the run method terminates the thread }

  第一種寫法適用於後台下載文件拷貝以及類似情形第二種寫法適合游戲畫面刷新或者類似情形

  第一種寫法利用了interrupt方法作為終止的請求使得循環跳出run方法執行完畢而第二種方法則是利用當線程sleep的時候調用interrupt會拋出InterruptedException從而跳出了循環進而線程執行到結束

  事實上這兩種寫法的區別就在於第二種使用了sleep

  在我們的使用示例中對應這兩種方法的使用代碼如下

  這一段是實現文件拷貝的

  private class CopyRunnable implements Runnable {

  @Override

  public void run() {

  File fromFile = new File(EnvironmentgetExternalStorageDirectory()

  getAbsolutePath() + /abcexe

  long fileLength = fromFilelength()

  long copyedLength = ;

  File toFile = new File(EnvironmentgetExternalStorageDirectory()

  getAbsolutePath() + /abc_exe

  if (toFileexists()) {

  toFiledelete()

  }

  try {

  FileInputStream fileInputStream = new FileInputStream(fromFile)

  FileOutputStream fileOutputStream = new FileOutputStream(

  toFile true)

  byte[] buffer = new byte[];

  int readLength = ;

  while (!ThreadcurrentThread()isInterrupted()

  && (readLength = fileInputStreamread(buffer)) != ) {

  fileOutputStreamwrite(buffer bufferlength)

  copyedLength += readLength;

  int progress = (int)

  ((float) copyedLength / fileLength *

  handlerobtainMessage( progress sendToTarget()

  }

  } catch (FileNotFoundException e) {

  eprintStackTrace()

  } catch (IOException e) {

  eprintStackTrace()

  } finally {

  handlerobtainMessage(sendToTarget()

  }

  }

  }

  這一段是實現矩形繪圖的

  private class DrawRunnable implements Runnable {

  @Override

  public void run() {

  try {

  while (true) {

  long beginTime = SystemcurrentTimeMillis()

  paintsetColor(getColor())

  getCoor()

  postInvalidate()

  long endTime = SystemcurrentTimeMillis()

  if (endTime beginTime < ) {

  Threadsleep( (endTime beginTime))

  }

  }

  } catch (InterruptedException e) {

  eprintStackTrace()

  } finally {

  }

  }

  }

  實際上這兩種寫法都是利用了interrupt方法的特點通過線程的中斷置位或者異常拋出來跳出循環進而終結線程如果對這段代碼感興趣可以到文章最後下載代碼

  最後做一下方法總結

  void interrupt()

  向線程發送中斷請求線程的中斷狀態將被設置為true如果目前該線程被一個sleep調用阻塞那麼InterruptedException異常被拋出

  static boolean interrupted()

  測試當前線程(即正在執行這一命令的線程)是否被中斷注意這是一個靜態方法這一調用會產生副作用它將當前線程的中斷狀態設置為false

  boolean isInterrupted()

  測試線程是否被中斷不像靜態的中斷方法這一調用不會改變線程的中斷狀態

  static Thread currentThread()

  返回代表當前執行線程的Thread對象


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27558.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.