zoukankan      html  css  js  c++  java
  • 如何正确的停止一个线程

    ================================题外话=================================

    复习多线程的知识,偶然看到一道题:如何正确的停止一个线程?我第一反应是使用stop()方法停止,操作以后发现stop已经被废弃了。

    经过查找资料,发现是使用interrupt()进行中断标记然后在进行停止,特此写这篇随笔记录一下。

    ------------------------------------------------------------------------------------------------------------------------------------

    stop()、suspend()的缺点

    1.会导致一些清理工作没有进行,导致一些资源没有得到回收,导致内存泄漏;

    2.stop()停止线程会导致对锁定的对象进行解锁,在多线程情况下导致数据不一致问题。

    interrupt()方法

    interrupt()方法为为调用该方法的线程对象设置一个中断标志,注意!这里是设置一个中断标志,丝毫不耽误线程没羞没臊的运行。请看例子

     1 public class App {
     2     public static void main(String[] args) {
     3 
     4         try {
     5             MyThread thread = new MyThread();
     6             thread.start();
     7             thread.interrupt();
     8             System.out.println("执行了interrupt方法");
     9         } catch (Exception e) {
    10             e.printStackTrace();
    11         }
    12     }
    13 
    14 }
    15 
    16 class MyThread extends Thread {
    17     
    18     public void run() {
    19         try{
    20             for(int i=0;i<5000;i++){
    21                 System.out.println(i);
    22             }
    23         }catch(Exception e){
    24             e.printStackTrace();
    25         }
    26     }
    27 }

    运行结果:

    1 ....
    2 4992
    3 4993
    4 4994
    5 4995
    6 4996
    7 4997
    8 4998
    9 4999

    说明在调用了interrupt之后,线程并不会停止。

    使用interrupted()和isInterrupted()判断中断状态

    interrupted()作用于调用该方法所在的线程,而不是调用者所在的线程,即无论哪个线程对象调用interrupted()方法,最后结果都是该方法所在线程的状态结果。

    isInterrupted()作用于调用该方法的线程,即谁调用显示谁的中断状态。

    并且interrupted()在第二次调用的时候,会恢复线程的状态,即第一次调用如果是中断状态,第二次调用将恢复为非中断状态。

    isInterruted()仅仅是查看线程的中断状态,并不会改变状态。请看下面例子

     1 public class App {
     2     public static void main(String[] args) {
     3 
     4         try {
     5             MyThread thread = new MyThread();
     6             thread.start();
     7             thread.interrupt();
     8             
     9             //显示的是主线程的中断状态,所以显示false
    10             System.out.println("调用interrupted():  " + thread.interrupted());
    11             
    12             //main主线程调用interrupt(),是主线程状态为中断
    13             Thread.currentThread().interrupt();
    14             
    15             //这里也可以使用Thread.currentThread().interrupted(),效果是一样的,具体原因看上面介绍
    16             System.out.println("第一次调用interrupted():  " + thread.interrupted());
    17             //第二次调用,interrupted()方法又将状态恢复
    18             System.out.println("第二次调用interrupted():  " + thread.interrupted());
    19             
    20             System.out.println("-------------------------------------------------");
    21             
    22             //而isInterrupted()返回的是调用者线程的中断状态,而且多次调用状态不会恢复
    23             System.out.println("第一次调用isInterrupted():  " + thread.isInterrupted());
    24             System.out.println("第二次调用isInterrupted():  " + thread.isInterrupted());
    25         } catch (Exception e) {
    26             e.printStackTrace();
    27         }
    28     }
    29 }
    30 
    31 class MyThread extends Thread {
    32     
    33     public void run() {
    34         try{
    35             while(true){
    36                 
    37             }
    38         }catch(Exception e){
    39             e.printStackTrace();
    40         }
    41     }
    42 }

    运行结果为:

    1 调用interrupted():  false
    2 第一次调用interrupted():  true
    3 第二次调用interrupted():  false
    4 -------------------------------------------------
    5 第一次调用isInterrupted():  true
    6 第二次调用isInterrupted():  true

    注意:如果线程在睡眠状态中,线程状态被修改为interrupted,这是将抛出java.lang.InterruptedException异常,线程将会停止

    下面进入正题,如何正确的停止一个线程

    有以下几个方式:

    使用break停止线程:判断线程状态为中断时,使用break跳出run()方法中的循环,缺点是虽然跳出了循环体,但是循环体外的程序还会得到执行,并不能到达立即停止的效果

    使用return停止线程:判断线程状态为中断时,使用return退出run()方法

    抛出异常停止线程:通过抛出一个异常来停止线程,这是比较推荐的方式

    这三种方式实现基本相似,我就拿异常法进行举例了(偷懒)。

     1 public class App {
     2     public static void main(String[] args) {
     3 
     4         try {
     5             MyThread thread = new MyThread();
     6             
     7             thread.start();
     8             Thread.sleep(2000);
     9             thread.interrupt();
    10                         
    11             while(true){   //主线程将一直运行
    12                 
    13             }
    14         } catch(Exception e){
    15             e.printStackTrace();
    16         }
    17     }
    18 }
    19 
    20 class MyThread extends Thread {
    21     
    22     public void run() {
    23         try{
    24             while(true){
    25                 if(isInterrupted()){
    26                     throw new InterruptedException();
    27                 }
    28             }
    29         }catch(InterruptedException e){
    30             System.out.println("由于异常退出线程");
    31             e.printStackTrace();
    32         }finally{
    33             System.out.println("这是线程的finally");
    34         }
    35     }
    36 }

     运行结果:

    1 java.lang.InterruptedException
    2     at com.sunyong.thread.stop.MyThread.run(App.java:31)
    3 由于异常退出线程
    4 这是线程的finally
  • 相关阅读:
    详解Android Intent
    【JAVA EE企业级开发四步走完全攻略】
    撼动IT界的10大编程语言
    System.getProperty() 常用值
    Android List,Adapter相关
    为程序员量身定制的12个目标
    java 算法数据
    JAVA基础之理解JNI原理
    Java 工厂模式
    linux下C语言读取网卡MAC地址
  • 原文地址:https://www.cnblogs.com/duodushuduokanbao/p/9567433.html
Copyright © 2011-2022 走看看