Java 基本功之中断线程的理解

 我来答
大沈他次苹0B
2022-11-09 · TA获得超过7322个赞
知道大有可为答主
回答量:3059
采纳率:100%
帮助的人:177万
展开全部

  设想这样的情景 我们的应用在某一个时间段内 需要一个子线程不停的在后台运行 这可能是一个下载过程 是一个对服务端socket的监听 也可能是一个绘图的计算过程 当我们想要终止线程的时候 我们会怎样做呢?是设定一个标志变量来控制跳出循环?还是使用thread stop()?又或者是设置thread = null?

  有的时候我们需要一种规范的思路 使用规范的方法来解决一类问题

  我们首先要明白 线程终止的条件 有三种情况

   当线程的run方法执行方法体中最后一条语句后

   当执行retutrn语句返回时

   当出现了在方法中没有捕获的异常时

  在Java的早期版本中 还有一个stop方法 其他线程可以调用它终止线程 但是这个方法已经被弃用了 所以还在用的同学就不要继续用了

  我们的正确思路是 使用interrupt方法来终止我们的线程

  首先要理解interrupt方法做了什么 每一个线程都有一个中断状态 这是一个boolean标志 当线程调用了interrupt方法时 这个中断状态就会被置位 如果我们要检查中断状态 可以使用Thread currentThread() isInterrupted()来获得是否中断

  但是如果线程被阻塞了(sleep or wait) 当我们调用了interrupt方法的时候 就会产生InterruptedException异常 这是我们可以利用的地方

  同样的 如果中断状态先被置位了 然后我们调用了sleep方法 线程不会休眠 相反 它将清除中断状态 然后抛出InterruptedException

  我们调用了interrupt并不意味着线程会终止 线程是否会终止 以及会如何继续 是程序员来控制的

  在本文中我们将会讨论终止线程的规范用法 然后在一个例子中实际应用 在这个例子中我们模拟了文件拷贝和游戏绘图两种情形 做出的效果如下图所示 点击start后上方进度条会显示文件拷贝的进度 点击end则会停止拷贝 点击draw会在画面中不停绘制各种各样的矩形 点击stop则会停止绘制

  首先我们来看两种情形的后台线程写法

  public void run() {

  try{

  …

  while(!Thread currentThread isInterrupted() && 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

  Thread sleep(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(Environment getExternalStorageDirectory()

   getAbsolutePath() + /abc exe )

  long fileLength = fromFile length()

  long copyedLength = ;

  File toFile = new File(Environment getExternalStorageDirectory()

   getAbsolutePath() + /abc_ exe )

  if (toFile exists()) {

  toFile delete()

  }

  try {

  FileInputStream fileInputStream = new FileInputStream(fromFile)

  FileOutputStream fileOutputStream = new FileOutputStream(

  toFile true)

  byte[] buffer = new byte[ ];

  int readLength = ;

  while (!Thread currentThread() isInterrupted()

  && (readLength = fileInputStream read(buffer)) != ) {

  fileOutputStream write(buffer buffer length)

  copyedLength += readLength;

  int progress = (int)

  ((float) copyedLength / fileLength * )

  handler obtainMessage( progress ) sendToTarget()

  }

  } catch (FileNotFoundException e) {

  e printStackTrace()

  } catch (IOException e) {

  e printStackTrace()

  } finally {

  handler obtainMessage( ) sendToTarget()

  }

  }

  }

  这一段是实现矩形绘图的

  private class DrawRunnable implements Runnable {

  @Override

  public void run() {

  try {

  while (true) {

  long beginTime = System currentTimeMillis()

  paint setColor(getColor())

  getCoor()

  postInvalidate()

  long endTime = System currentTimeMillis()

  if (endTime beginTime < ) {

  Thread sleep( (endTime beginTime))

  }

  }

  } catch (InterruptedException e) {

  e printStackTrace()

  } finally {

  }

  }

  }

  实际上这两种写法都是利用了interrupt方法的特点 通过线程的中断置位或者异常抛出来跳出循环进而终结线程 如果对这段代码感兴趣 可以到文章最后下载代码

  最后做一下方法总结

  void interrupt()

  向线程发送中断请求 线程的中断状态将被设置为true 如果目前该线程被一个sleep调用阻塞 那么 InterruptedException异常被抛出

  static boolean interrupted()

  测试当前线程(即正在执行这一命令的线程)是否被中断 注意 这是一个静态方法 这一调用会产生副作用 它将当前线程的中断状态设置为false

  boolean isInterrupted()

  测试线程是否被中断 不像静态的中断方法 这一调用不会改变线程的中断状态

  static Thread currentThread()

lishixinzhi/Article/program/Java/gj/201311/27558

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式