多线程---停止线程

来源:互联网 发布:micro800编程软件下载 编辑:程序博客网 时间:2024/05/17 05:12

停止线程在java语言中并不像break,return那样干脆,需要一定的技巧性。

之前认为线程的停止很简单,一个interupt()方法就完成了,事实上这是完全错误的,线程的停止API中确实提供了一个简单的方法stop(),但是在新的API中已经被标记过时了,原因就是他不够安全。
在java中提供了2中方法用来终止正在运行的线程:
1)使用退出标志,使线程正常退出,也就是run()完成后线程终止
2)使用stop强行终止线程,但是不推荐,产生不可预料的后果
3)使用interrupt终止线程

  • interrupt()并不能停止线程
    可能我说了,你也不信,那就来个demo验证一下
public class A extends Thread {    @Override    public void run() {        for(int j=0;j<50000;j++){            System.out.println("j="+j);        }    }}public static void main(String[] args) {        A a = new A();        a.start();        try {            Thread.sleep(2000);            a.interrupt();        } catch (InterruptedException e) {            e.printStackTrace();            System.out.println(e.toString());        }    }

看一下打印结果:
image_1b4dotc0e10261j0npcq1v2h1spf9.png-18.7kB

没少打印吧,这就说明interrupt()并不能停止线程,调用interrupt()仅仅是在当前线程中打了一个停止标记,并不是真的停止线程。

  • 正确判定线程的运行状态
    想要正确的停止线程,必须要知道线程处于生命周期的什么时期,必须要了解这几个API.
    1) interrupted();
    2) isInterrupted();

先看一下这2个的介绍:
image_1b4dpfp1d1pgmq0g174q1i9q1h3em.png-20.1kB

image_1b4dpgfdnt5p7fl1vb21um6s9m13.png-13.5kB

这里说的很清晰了,interrupted()测试当前线程是否中断,并且清除中断状态;isInterrupted()是测试线程是否已经中断,并不影响线程的状态;
下面来个demo说明一下:

    public static void main(String[] args) {        A a = new A();        a.start();        try {            Thread.sleep(2000);            a.interrupt();            System.out.println("interrupted:"+a.interrupted());            System.out.println("interrupted:"+a.interrupted());            System.out.println("is interrupted:"+a.isInterrupted());            System.out.println("is interrupted:"+a.isInterrupted());        } catch (InterruptedException e) {            e.printStackTrace();            System.out.println(e.toString());        }    }

打印结果
image_1b4dpqrvt1m3r1mjlni11i3l10521g.png-4.4kB

再来修改一下:

public static void main(String[] args) {        A a = new A();        a.start();        try {            Thread.sleep(2000);            a.interrupt();            Thread.currentThread().interrupt();            System.out.println("interrupted:"+Thread.interrupted());            System.out.println("interrupted:"+Thread.interrupted());            System.out.println("is interrupted:"+a.isInterrupted());            System.out.println("is interrupted:"+a.isInterrupted());        } catch (InterruptedException e) {            e.printStackTrace();            System.out.println(e.toString());        }    }

再看一下打印:
image_1b4dq02lqmrf1sqefooddd1dh01t.png-4.1kB

这个结果就印证了API上对interrupted()的说明,是测试当前线程的状态,并清除中断状态。

分析:先看第一种情况,只是执行了a.interrupt(),虽然也执行了a.interrupted(),但是还是检测的当前线程,主线程(Main)一直没有中断,所以第一次的interrupted=false;
第二种情况:Thread.currentThread.interrupt()中断了主线程,所以第一次interrupted=true,由于他还有个作用清除当前线程的中断状态,所以第二次的时候interrupted=false;

在修改一下,看下isInterrupted

public class A extends Thread {    @Override    public void run() {        for(int j=0;j<500000;j++){            System.out.println("j="+j);            if(this.isInterrupted()){                System.out.println("is interrupted:"+this.isInterrupted());                System.out.println("is interrupted:"+this.isInterrupted());                break;            }        }    }}public static void main(String[] args) {        A a = new A();        a.start();        try {            Thread.sleep(2000);            a.interrupt();        } catch (InterruptedException e) {            e.printStackTrace();            System.out.println(e.toString());        }    }

看下打印结果:
image_1b4dtqtvl1h6a1k601bog65re7i2a.png-3.7kB
这里看到isInterrupted()并不会清除线程的终止状态,所以2次都会true,虽然状态是ture,只是跳出了循环,但是线程仍然会运行。

  • 异常法停止线程
    有了前面的检测线程状态的API,就可以为线程的停止,提供依据
public class A extends Thread {    @Override    public void run() {        try{            for(int j=0;j<500000;j++){                System.out.println("j="+j);                if(this.isInterrupted()){                    throw new InterruptedException("thread is interrupted");                }            }            System.out.println("for 之后运行");            //do some        }catch(Exception e){            System.out.println(e.toString());        }    }}public static void main(String[] args) {        try {            A a = new A();            a.start();            Thread.sleep(1000);            a.interrupt();        } catch (InterruptedException e) {            e.printStackTrace();            System.out.println(e.toString());        }    }

看下打印结果
image_1b4dubulk16vc43819sm2nnrhs2n.png-7kB
线程确实停止了,for语句后的也没有执行

  • return停止线程
    将上面代码中的 throw new InterruptedException(“thread is interrupted”);改为return;也可以进行线程的终止,但是最好还是用异常法,因为catch块中的异常可以向上进行抛,使线程停止事件得以传播

  • 使用stop停止线程(不建议使用)
    先看一下使用会有什么样的不良后果,

public class SynObject {    private String name="a";    private String pwd="aaa";    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPwd() {        return pwd;    }    public void setPwd(String pwd) {        this.pwd = pwd;    }    synchronized public void printString(String name,String pwd){        try {            this.name = name;            Thread.sleep(100*1000);            this.pwd = pwd;        } catch (InterruptedException e) {            e.printStackTrace();        }    }}public class A extends Thread {    private SynObject object;    public A (SynObject object){        this.object = object;    }    @Override    public void run() {        object.printString("b", "bbb");    }}    public static void main(String[] args) throws Exception {            SynObject object = new SynObject();            A a = new A(object);            a.start();            Thread.sleep(500);            a.stop();            System.out.println("name:"+object.getName()+",pwd:"+object.getPwd());    }

这个逻辑很简单,object属性是有进行初始化的,printString对属性进行了重新赋值,看下结果
image_1b4e0pa8o1ro5p3aoqd6p4176934.png-7.2kB

虽然线程是被及时停止了,但是获得的结果并不是我们预想的。stop()强行停止,可能使一些清理性的工作得不到完成,造成内存的泄漏;另外一个就是对锁定对象进行了“解锁”,导致数据得不到同步处理,出现数据不一致的问题;所以最好不要用

  • b
0 0
原创粉丝点击