• 1.7停止线程


    线程停止:在线程处理完任务之前,停掉正在做的操作,也就是放弃当前操作。

    在java中有三种方法可以实现线程的停止:

    1. 使用退出标志,使线程正常退出,也就是当run方法执行完后线程终止。
    2. 使用stop强行终止线程。但是不推荐这个方法,因为stop与suspend以及resume一样,都是作废过期的方法,使它们产生不可预期的结果。
    3. 使用interrupt()方法中断线程。该方法不会终止一个线程,还需要加入一个判断才能够完成线程的终止。

    1.7.1停不了的线程

    本例中调用interrupt()方法来停止线程,但是interrupt()方法并不像循环中的break关键字一样可以立即起效,interrupt()方法仅仅是在当前线程中打了一个停止的标记,并没有真正停止线程。

    线程代码:

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

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                MyThread mt = new MyThread();
                mt.start();
                mt.sleep(2000);
                mt.interrupt();
            } catch (Exception e) {
                System.out.println("main Catch");
                e.printStackTrace();
            }
        }
    }

    执行结果:

    实际上代码执行了50000行,并没有出现线程的停止。

    1.7.2判断线程是否是停止状态:

    在Java的SDK中,Thread.java类里提供了两种方法判断线程是否停止

    this.interrupted()的代码:

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

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread1 t1 = new Thread1();
                t1.start();
                t1.sleep(1000);
                t1.interrupt();
                System.out.println("是否停止了1? = " + Thread.interrupted());
                System.out.println("是否停止了2? = " + Thread.interrupted());
            } catch (Exception e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
        }
    }

    执行结果:

    分析:从打印结果来看线程并没有中断。this.interrupted()的解释是:测试当前线程是否中断,根据代码可以判断当前的线程为“main”线程。这里肯定是没有中断的,所以返回false。

    使main线程产生中断:

    执行代码:

    public class Main {
        public static void main(String[] args) {
            Thread.currentThread().interrupt();
            System.out.println("是否停止了1 ? = " + Thread.interrupted());
            System.out.println("是否停止了2 ? = " + Thread.interrupted());
            System.out.println("end!");
        }
    }

    执行结果:

    为什么这里第二次判断的时候返回false呢?

    interrupted()方法的解释:测试当前线程是否已经中断。线程的中断状态由该方法去除。

    可以预见,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用后已经清楚了线程的中断状态,且第二次调用在中断状态前,所以返回false)

    this.isInterrupted():

    该方法声明如下:

    public boolean isInterrupted()

    注:不是静态方法。

    线程代码:

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

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread1 thread = new Thread1();
                thread.start();
                Thread.sleep(1000);
                thread.interrupt();
                System.out.println("是否停止1 ? = " + thread.isInterrupted());
                System.out.println("是否停止2 ? = " + thread.isInterrupted());
            } catch (Exception e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
            System.out.println("end!");
        }
    }

    结果:

    ????惊了这为什么就不一样呢????(一脸懵逼。代码应该是没问题的,有没有大佬来指点一下。)(我修改了休眠时间什么的还是现实false。。反倒是去掉休眠时间会返回true,我有点烦)

    1. this.interrupted():测试当前线程是否已经是中断状态,执行后具有将状态标志清楚为false的功能。
    2. this.isInterrupted():测试线程Thread对象是否已经是中断状态,但不能清楚状态标志。

    1.7.3能停止的线程——异常法:

    线程代码:

    public class Thread2 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 500000; i++) {
                if (this.interrupted()) {
                    System.out.println("已经是停止状态! 我要退出了!");
                    break;
                }
                System.out.println("i = " + (i + 1));
            }
        }
    }

    运行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread2 thread = new Thread2();
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
            } catch (Exception e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
            System.out.println("end!");
        }
    }

     结果:

    注:实际上此时如果线程的for循环外还有代码的话还是会继续执行的(Thread.interruped()调用后会移除线程的停止状态,即线程会继续调用run()内部的代码)

    线程代码:

    public class Thread3 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 500000; i++) {
                if (Thread.interrupted()) {
                    System.out.println("已经是停止状态了,我要退出了!");
                    break;
                }
                System.out.println("i = " + (i + 1));
            }
            System.out.println("我被输出说明线程已经结束停止状态,并继续执行。");
        }
    }

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread3 thread = new Thread3();
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
            } catch (Exception e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
            System.out.println("end!");
        }
    }

    执行结果:

    如果解决后续语句继续输出的问题?

    这时候利用的就是抛出异常来解决。(但是我个人认为,你换一个判断方法不就行了?调用对象的this.isInterrupt(),不过由于这是展示如何停止一个线程的,标题名还是异常法。。就这样吧)

    线程代码:

    public class Thread4 extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 500000; i++) {
                    if (Thread.interrupted()) {
                        System.out.println("已经停止了!我要退出了!在此时抛出异常,使线程结束。");
                        throw new InterruptedException();
                    }
                    System.out.println("i = " + (i + 1));
                }
                System.out.println("我在for循环下面,是本来可以执行的代码。");
            } catch (Exception e){
                System.out.println("进入线程代码的异常处理中");
                e.printStackTrace();
            }
        }
    }

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread4 thread = new Thread4();
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
            } catch (Exception e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
            System.out.println("end!");
        }
    }

    执行结果:

     1.7.4在沉睡中停止:

    如果线程在sleep()状态下停止线程,会有什么效果呢?

    线程代码:

    public class Thread5 extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("run begin");
                Thread.sleep(20000000);
                System.out.println("run end");
            } catch (Exception e) {
                System.out.println("在沉睡中被停止!进入catch 停止状态为:" + this.isInterrupted());
                e.printStackTrace();
            }
        }
    }

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread5 thread = new Thread5();
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
            } catch (Exception e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
            System.out.println("end!");
        }
    }

     执行结果:

    从结果看,在sleep下停止某一线程,会进入catch语句,并且清楚之前的状态值,使之变成false。

    这次是先停止,然后再睡眠:

    线程代码:

    public class Thread6 extends Thread {
        @Override
        public void run() {
            try {
                for (int i = 0; i < 100000; i++) {
                    System.out.println("i=" + (i + 1));
                }
                System.out.println("run begin");
                Thread.sleep(200000);
                System.out.println("run end");
            } catch (Exception e) {
                System.out.println("先interrupt(),再遇到了sleep!进入catch");
                e.printStackTrace();
            }
        }
    }

    执行代码:

    public class Main {
        public static void main(String[] args) {
            Thread6 thread = new Thread6();
            thread.start();
            thread.interrupt();
            System.out.println("end!");
        }
    }

    执行结果:

    也就是说。不论是先睡眠,然后再睡眠中被停止,还是先停止,在睡眠。都会报错。

    1.7.5能停止的线程——暴力停止:

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

    线程代码:

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

    执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread7  thread = new Thread7();
                thread.start();
                Thread.sleep(5000);
                thread.stop();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    执行结果:

     1.7.6方法stop()与java.lang.ThreadDeath异常:

    调用stop()方法时,会抛出java.lang.ThreadDeath异常,但在通常情况下,此异常不需要显示地捕捉。

    创建线程代码:

    public class Thread8 extends Thread {
        @Override
        public void run() {
            try {
                this.stop();
            } catch (ThreadDeath e) {
                System.out.println("进入了catch()方法中");
                e.printStackTrace();
            }
        }
    }

     执行代码:

    public class Main {
        public static void main(String[] args) {
            Thread8 thread = new Thread8();
            thread.start();
        }
    }

     执行结果:

    注:stop()方法已经作废,因为如果强制停止线程会导致一些清理的工作无法完成,另外一种情况就是对锁定的对象进行了“解锁”,导致数据得不到同步的处理,出现数据不一致的问题。

    1.7.7释放锁的不良后果:

    使用stop()释放锁将会给数据造成不一致性的结果。如果出现这种情况,程序执行的数据就会遭到破坏,最终导致程序的执行出现异常。

    同步类代码:

    public class SynchronizedObject {
        private String username = "a";
        private String password = "aa";
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        synchronized public void printString(String username,String password) {
            try {
                this.username = username;
                Thread.sleep(100000);
                this.password = password;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    线程代码:

    public class Thread9 extends Thread {
        private SynchronizedObject object;
    
        public Thread9(SynchronizedObject object) {
            this.object = object;
        }
    
        @Override
        public void run() {
            object.printString("b","bb");
        }
    }

    执行代码: 

    public class Main {
        public static void main(String[] args) {
            try {
                SynchronizedObject object = new SynchronizedObject();
                Thread9 thread = new Thread9(object);
                thread.start();
                Thread.sleep(500);
                thread.stop();
                System.out.println(object.getUsername() + "  " + object.getPassword());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

     执行结果:

    注:由于stop()方法将锁释放,此时还没有对run()的方法调用完毕,导致数据出现不一致现象。(仅仅username被修改,线程在休眠的过程中被杀死,导致密码的修改没有进行)。

    1.7.8使用return停止线程:

    使用interrupt()与return结合使用也能实现停止线程的效果。

    线程代码:

    public class Thread10 extends Thread {
        @Override
        public void run() {
            while (true) {
                if (this.isInterrupted()) {
                    System.out.println("停止了!");
                    return;
                }
                System.out.println("timer = " + System.currentTimeMillis());
            }
        }
    }

     执行代码:

    public class Main {
        public static void main(String[] args) {
            try {
                Thread10 thread = new Thread10();
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    执行结果:

    从目前来看,这是一种很合理的方式来实现线程的停止。如果以后能看到更多的东西会回来对笔记进行修正的。

    源码地址:https://github.com/lilinzhiyu/threadLearning

    本文内容是书中内容兼具自己的个人看法所成。可能在个人看法上会有诸多问题(毕竟知识量有限,导致认知也有限),如果读者觉得有问题请大胆提出,我们可以相互交流、相互学习,欢迎你们的到来,心成意足,等待您的评价。

  • 相关阅读:
    jdk环境一键配置
    IIS 浏览aspx页面出现 无法显示 XML 页
    ASP.NET MVC(三)
    ASP.NET MVC(二)
    ASP.NET MVC (一)
    Fatal error: Call to a member function bind_param() on a non-object in
    Eclipse字符集设置方式
    mysql 管理工具
    win7 IIS发布项目遇到的问题
    php 环境的搭建
  • 原文地址:https://www.cnblogs.com/lilinzhiyu/p/7942730.html
Copyright © 2020-2023  润新知