Java停止线程及有锁时停止方法

来源:互联网 发布:淘宝客推广网站怎么建 编辑:程序博客网 时间:2024/06/04 18:53

当我们刚学完Thread一个线程t1之后,迫不及待地键入t1.start()开始启动线程,肯定思考过如何将这个线程停下来

其实原理只有一个,那就是让run方法结束

要知道开启多线程运行,其运行代码通常都是循环结构,只要控制住循环就可以让run方法结合苏,也就是线程结束

比如写个代码

class StopThread implements Runnable{       public synchronized void  run()    {        while(true)        {            System.out.println(Thread.currentThread().getName()+"...run");        }       }   }public class StopThreadDemo {    public static void main(String[] args) {        StopThread st=new StopThread();        Thread t1=new Thread(st);        Thread t2=new Thread(st);        t1.start();        t2.start();        int num=0;        while(true)        {            if(num++==60)            {                break;            }            System.out.println(Thread.currentThread().getName()+"......"+num);        }    }}

这个小程序很简单,就是让两个线程一直跑,跑到60次之后就break,想法是好的,这个程序我是不会去跑的,因为我知道这个是无限循环,while(true)这个标记让它一直转

所以如果while(true)这个标记能够控制住,这个小程序就能停下来

  • 可以定义个flag=true,再定义个changeFlag()方法,这个方法里面将flag切换为false
    将while(true)改为while(false)
  • 如果num++=60,就调用changeFlag方法
class StopThread implements Runnable{       private boolean flag=true;//**************    public void  run()    {        while(flag)//**************        {            System.out.println(Thread.currentThread().getName()+"...run");        }       }    public void changeFlag()//**************    {    flag=false;    }   }public class StopThreadDemo {    public static void main(String[] args) {        StopThread st=new StopThread();        Thread t1=new Thread(st);        Thread t2=new Thread(st);        t1.start();        t2.start();        int num=0;        while(true)        {            if(num++==60)            {                st.changeFlag();//**************                break;            }            System.out.println(Thread.currentThread().getName()+"......"+num);        }    }}

可以看到各线程运行之后安稳地停了下来

但是有一种情况,程序也停不下来
就是同步

public synchronized void  run()    {        while(flag)//**************        {            try {                wait();            } catch (InterruptedException e) {                System.out.println(Thread.currentThread().getName()+"...Exception");                flag=false;            }            System.out.println(Thread.currentThread().getName()+"...run");        }       }

*run()方法若是同步函数,且在while内try一个wait(),抛出InterruptedException,这时候运行也做了changeFlag()改变,程序就不会停下来;

末尾没有

如图,程序没有停下来,但是并不占用资源,不是死循环,因为wait在那儿了

  • 当主线程while(true)的时候一直在转,到num==60的时候,st.changeFlag()也读了。可是开启两个线程之后,无论什么时候抢到CPU资源,都去public
    synchronized void run(){}里面去运行
  • Thread-0进去之后,拿到一把锁,然后wait()了,放弃了资格,然后Thread-1进去也释放资格了,然后这两个都挂在这儿不动了;
  • 主线程执行完了,还有两个线程存活,这个就是问题,改变了标记flag但是没有结束线程

也就是当线程处于冻结状态,就不会读取到标记,那么线程就不会结束。
**只有wait()结束之后再去while(flag)循环,读到标记才能结束。

我们可以强制做这件事情

在Thread中提供了一个方法叫interrupt()方法,叫做中断线程:如果线程在调用Object类的wait()等方法,或者join和sleep受阻,则其终端状态江北清除;中断状态也就是Wait,还会收到一个InterruptException;但是中断并不是stop,只是挂起
这时候,我可以强制清除其中断状态,强制地恢复到运行状态

wait就像是催眠,催眠师拿个表将他吹眠之后进入中断状态,随后又用他的方法把他叫醒了;但现在,催眠师又把他催眠到中断状态,然后出国了。。。这时候要他醒过来怎么办,我又不会催眠师的方法,那我就一砖头下去把他呼醒得了

但是受伤了,发生异常了

现在对t1和t2下手,改变主函数的if内部:

if(num++=60){    t1.interrupt();    t2.interrupt();    st.changeFlag();    break;}

完整如下:

class StopThread implements Runnable{       private boolean flag=true;    public  synchronized void  run()    {        while(flag)        {            try {                wait();            } catch (InterruptedException e) {                System.out.println(Thread.currentThread().getName()+"...Exception");                //flag=false;            }            System.out.println(Thread.currentThread().getName()+"...run");        }    }    public void changeFlag()    {    flag=false;    }   }public class StopThreadDemo {    public static void main(String[] args) {        StopThread st=new StopThread();        Thread t1=new Thread(st);        Thread t2=new Thread(st);        t1.start();        t2.start();        int num=0;        while(true)        {            if(num++==60)            {                t1.interrupt();                //st.changeFlag();                break;            }            System.out.println(Thread.currentThread().getName()+"......"+num);        }        System.out.println("over");    }}

这里写图片描述

看打印结果,Thread-0出现了终端异常,这就是因为t1的中断状态被强制清除了,所以产生了中断异常,但是程序还挂着不动,可以看到catch到异常之后又处理了一次,打印了Thread_0…run,之后此线程又回到了while(flag), 此时flag依旧为true,接着wait,又挂了

所以知道这个原因之后就很好解决了,
也就是只要发生异常,就代表有人在强制清除其中断状态,那么就在处理这个异常的时候,将flag标记为false,就可以完美结束了。

class StopThread implements Runnable{       private boolean flag=true;    public synchronized void  run()    {        while(flag)        {            try {                wait();            } catch (InterruptedException e) {                System.out.println(Thread.currentThread().getName()+"...Exception");                flag=false;            }            System.out.println(Thread.currentThread().getName()+"...run");        }    }    public void changeFlag()    {        flag = false;    }}public class StopThreadDemo {    public static void main(String[] args) {        StopThread st=new StopThread();        Thread t1=new Thread(st);        Thread t2=new Thread(st);        t1.start();        t2.start();        int num=0;        while(true)        {            if(num++==60)            {                t1.interrupt();                t2.interrupt();                st.changeFlag();                break;            }            System.out.println(Thread.currentThread().getName()+"......"+num);        }        System.out.println("over");    }}

总结就是

  • 当没有指定的方法让冻结的线程恢复到运行状态时,这就需要对冻结进行清除
    强制让线程恢复到运行状态中来,就可以操作标记flag,让线程结束

  • Thread类提供该方法,interrupt( );

1 0
原创粉丝点击