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

当我们刚学完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);
        }
    }
}

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

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

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()改变,程序就不会停下来;

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

如图,程序没有停下来,但是并不占用资源,不是死循环,因为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");
    }
}

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

看打印结果,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( );

    原文作者:java锁
    原文地址: https://blog.csdn.net/G626316/article/details/54175381
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞