JavaSE-线程停止

        线程停止在Java中是一项很有技巧性的操作,虽然看起来很简单,但是我们必须做好防范措施,以便达到预期的效果。

        例如,停止一个线程可以直接用Thread.stop()方法,虽然它可以停止一个正在运行的线程,但是这个方法是不安全的,而且它是已经被弃用的方法。所以不建议使用该方法。大多数时候,停止一个线程使用Thread.interrupt()方法,这里的停止,并不是终止。

在Java中有三种方法可以终止正在运行的线程

        1:使用退出标志,使线程正常退出,就是run()方法完成之后线程终止。

        2:使用stop()方法强制终止线程,但是这个方法是过期的,可能会产生不可预料的后果,所以不推荐使用这个方法。

        3:使用interrupt()方法中断线程。

使用退出标志使线程正常退出

class My_Thread implements Runnable{
    private boolean flag = true;
    @Override
    public void run() {
        int i = 1;
        while(flag){
            try{
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName()+" "+i);
                i++;
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

public class Main{
    public static void main(String[] args)throws Exception{
        My_Thread New_Thread = new My_Thread();
        Thread thread = new Thread(New_Thread,"新线程1");
        thread.start();
        Thread.sleep(2000);
        New_Thread.setFlag(false);
    }
}

        这种方法很好理解:在线程的运行过程中直接改变run()方法中的标记,使run()方法执行完毕,从而安全退出线程。

使用stop()方法暴力停止线程

class MyThread extends Thread{
    private int i = 0;
    @Override
    public void run() {
        try{
            while(true){
                i++;
                System.out.println("i="+i);
                Thread.sleep(1000);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

public class Main{
    @SuppressWarnings("all")
    public static void main(String[] args){
        try{
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(5000);
            myThread.stop();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

        我们可以发现线程被暴力停止之后运行图标变为灰色,线程直接退出了。

        stop()会解除线程获取的所有锁定,如果在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,stop()的不安全就体现在这里:假如有线程正在执行synchronized方法的赋值操作时,赋值执行到一半突然被stop了,锁被直接释放,这样就会产生不完整的残废数据,最终导致程序执行的流程错误。

扫描二维码关注公众号,回复: 759957 查看本文章

        我这里只是演示一下stop方法,在JDK中stop方法被注明是过期的方法,所以不建议在程序中使用stop方法。

interrupt()方法:

        interrupt()方法仅仅是在当前的线程中打了一个停止的标记,并不是真正的停止线程,而且interrupt()方法不像break那样马上就停止循环。

class MyThread extends Thread{
    private boolean flag = true;
    @Override
    public void run() {
        int i = 1;
        while(flag){
            try{
                Thread.sleep(1000);//因为是sleep引起的阻塞,所以线程调用了interrupt方法
                //清除了中断标志,抛出了一个InterruptedException异常
                boolean bool = Thread.currentThread().isInterrupted();
                if(bool){
                    System.out.println("非阻塞情况下 线程状态:"+bool);
                    break;
                }
                System.out.println(i+"  :"+Thread.currentThread().getName());
                i++;
            }catch (InterruptedException e){
                //中断标志被清除,并且设置为false
                System.out.println("退出");
                boolean bool = Thread.currentThread().isInterrupted();
                System.out.println(bool);
                return;//退出run方法,终端进程
            }
        }
    }
}

public class Main{
    public static void main(String[] args)throws InterruptedException{
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"子线程1");
        thread.start();
        Thread.sleep(2000);
        thread.interrupt();
        System.out.println("结束");
    }
}

        interrput()方法只是改变中断状态而已,不会中断一个正在运行的线程。这个方法完成的是,给受阻塞的线程发一个中断信号,这样受阻塞的线程就可以退出阻塞的状态。

        这里要注意的是:如果线程当前没有被阻塞,那么仅仅是线程的中断标志被修改为true而已,但是如果线程处于阻塞状态,那么再将中断标志设置成true后,还会有以下操作:

        如果是wait,sleep或者jion三个方法引起的阻塞,那么线程的中断标志会被重新设置成false,并且抛出一个异常,就是我上面代码的那个例子。大概的意思就是:如果线程在运行中,中断标志设置为true后,一旦线程调用了以上的三种方法的任一种,线程就会立刻抛出一个异常,并且中断标志被擦除,重新设置为false。


    在介绍这个方法之后,要再介绍两种方法:interrupted(),isinterrupted()

        1:interrupted()方法:测试当前线程是否已经中断。

        2:isinterrupted()方法:测试线程是否已经中断。

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

    public boolean isInterrupted() {
        return isInterrupted(false);
    }

        这两个方法还是有区别的,首先看一下this.interrupt()的解释:测试当前线程是否已经中断,当前线程是指在运行this.interrupt()方法的线程,我先用一段代码来示例。

public class Main{
    @SuppressWarnings("all")
    public static void main(String[] args){
        Thread.currentThread().interrupt();
        System.out.println("当前线程是否终止:"+Thread.interrupted());
        System.out.println("当前线程是否终止:"+Thread.interrupted());
    }
}

        这段代码的意思是终止主方法并判断其是否中断,但是连续调用两次interrupted方法的结果并不一样,原因是interrupted方法具有擦除状态的功能。所以才会一次true一次false。

        但是,isinterrupted方法在用于这种情况时结果是这样的

class MyThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i<5;i++){
            System.out.println(i);
        }

    }
}


public class Main{
    @SuppressWarnings("all")
    public static void main(String[] args){
        Thread New_Thread = new MyThread();
            New_Thread.start();
            New_Thread.interrupt();
            System.out.println("当前线程是否终止:" + New_Thread.isInterrupted());
            System.out.println("当前线程是否终止:" + New_Thread.isInterrupted());
    }
}

        最后,我们来看一下这两种方法的解释

        this.interrupted():测试当前线程是否处于中断状态,执行之后将状态标志清除为false

        this.isInterrupted():测试线程对象是否处于中断状态,不会清除状态标志。

我就先总结到这里,我要看运动会了......

猜你喜欢

转载自blog.csdn.net/qq_38449518/article/details/80090140