• java 线程interupt stop(dep)


    https://blog.csdn.net/zbw18297786698/article/details/53432879/

    1、Java中API自带的stop()方法,来终止线程

            查阅JDK,不难发现Thread提供了一个stop()方法,但是stop()方法是一个被废弃的方法。为什么stop()方法被废弃而不被使用呢?原因是stop()方法太过于暴力,会强行把执行一半的线程终止。这样会就不会保证线程的资源正确释放,通常是没有给与线程完成资源释放工作的机会,因此会导致程序工作在不确定的状态下。关于使用stop()方法,造成数据不同步的例子如下。

            下面代码模拟一个过程,读线程ReadObjectThread在读到对象的ID和Name不一致时,会输出这些对象;而写线程ChangeObjectThread总是写入连个相同的数值。但是在代码中因为使用了stop()强行停止线程,造成了数据的不同步。

        public class ThreadStopUnSafe {
            public static User user = new User();
         
            // 改变user变量的线程
            public static class ChangeObjectThread extends Thread {
                @Override
                public void run() {
         
                    while (true) {
                        synchronized (ThreadStopUnSafe.class) {
                            int v = (int) (System.currentTimeMillis() / 1000);
                            user.setId(v);
                            // to do sth
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            user.setName(String.valueOf(v));
                        }
                        // 让出CPU,给其他线程执行
                        Thread.yield();
                    }
         
                }
         
            }
         
            // 读取user变量的线程
            public static class ReadObjectThread extends Thread {
                @Override
                public void run() {
         
                    while (true) {
                        synchronized (ThreadStopUnSafe.class) {
                            if (user.getId() != Integer.parseInt(user.getName())) {
                                System.out.println(user.toString());
                            }
                        }
                        // 让出CPU,给其他线程执行
                        Thread.yield();
                    }
         
                }
            }
         
            // 测试
            public static void main(String[] args) throws InterruptedException {
                new ReadObjectThread().start();
                while (true) {
                    Thread t = new ChangeObjectThread();
                    t.start();
                    Thread.sleep(150);
                                //使用stop()方法,强制停止线程
                    t.stop();
                }
            }
        }

                User.java的代码

        public class User {
            private int id;
            private String name;
         
            public User() {
                this(0, "0");
            }
         
            public User(int id, String name) {
                this.id = id;
                this.name = name;
            }
         
            public int getId() {
                return id;
            }
         
            public void setId(int id) {
                this.id = id;
            }
         
            public String getName() {
                return name;
            }
         
            public void setName(String name) {
                this.name = name;
            }
         
            @Override
            public String toString() {
                return "User [id=" + id + ", name=" + name + "]";
            }
         
        }

            程序的运行结果,出现了数据不一致的情况。

        User [id=1480649515, name=1480649514]
        User [id=1480649516, name=1480649515]

    2、使用boolean类型的变量,来终止线程

            那么如果需要停止一个线程时,应该怎么办?其实方法很简单,只是需要我们执行确定线程什么时候退出就可以了。仍用本例来说,只需要在ChangeObjectThread线程中增加一个stopMe()方法就可以了。

       

        public static class ChangeObjectThread extends Thread {
         
                // 用于停止线程
                private boolean stopMe = true;
         
                public void stopMe() {
                    stopMe = false;
                }
         
                @Override
                public void run() {
         
                    while (stopMe) {
         
                        synchronized (ThreadStopSafeBoolean.class) {
                            int v = (int) (System.currentTimeMillis() / 1000);
                            user.setId(v);
                            // to do sth
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            user.setName(String.valueOf(v));
                        }
                        // 让出CPU,给其他线程执行
                        Thread.yield();
                    }
         
                }
         
            }

              在上面的代码里面,定义了一个标记变量stopMe,用于指示线程是否需要退出。当stopMe()方法被调用时,stopme就会被赋值为false,此时在代码里面的while(stopMe)就会检测到这个改动,线程就退出了。
       

    3、java线程的中断

            中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的interrupt()方法对其进行中断操作。

            线程通过检查自身是否被中断来进行响应,线程通过方法isInterrupted()来进行判断是否被中断,也可以调用静态方法Thread.interrupted()对当前线程的中断标识位进行复位。如果该线程已经处于终结状态,即使该线程被中断过,在调用该线程对象的isInterrupted()时依旧会返回false。

            从Java的API中可以看到,许多声明抛出InterruptedException的方法(例如Thread.sleep(longmillis)方法,当线程在sleep()休眠时,如果被中断,这个异常就会产生)。这些方法在抛出InterruptedException之前,Java虚拟机会先将该线程的中断标识位清除,然后抛出InterruptedException,此时调用isInterrupted()方法将会返回false。

            在代码清单4-7所示的例子中,首先创建了两个线程,SleepThread和BusyThread,前者不停地睡眠,后者一直运行,然后对这两个线程分别进行中断操作,观察二者的中断标识位。

        import java.util.concurrent.TimeUnit;
         
        public class Interrupted {
            public static void main(String[] args) throws Exception {
                // sleepThread不停的尝试睡眠
                Thread sleepThread = new Thread(new SleepRunner(), "SleepThread");
                sleepThread.setDaemon(true);
                // busyThread不停的运行
                Thread busyThread = new Thread(new BusyRunner(), "BusyThread");
                busyThread.setDaemon(true);
                sleepThread.start();
                busyThread.start();
                // 休眠5秒,让sleepThread和busyThread充分运行
                TimeUnit.SECONDS.sleep(2);
                sleepThread.interrupt();
                busyThread.interrupt();
                System.out.println("SleepThread interrupted is "
                        + sleepThread.isInterrupted());
                System.out.println("BusyThread interrupted is "
                        + busyThread.isInterrupted());
                // 防止sleepThread和busyThread立刻退出
                TimeUnit.SECONDS.sleep(2);
            }
         
            static class SleepRunner implements Runnable {
                @Override
                public void run() {
                    while (true) {
                        try {
                            TimeUnit.SECONDS.sleep(10);
                        } catch (InterruptedException e) {
                            //e.printStackTrace();
                        }
                    }
                }
            }
         
            static class BusyRunner implements Runnable {
                @Override
                public void run() {
                    while (true) {
                    }
                }
            }
        }

            程序的运行结果

        SleepThread interrupted is false
        BusyThread interrupted is true

            从结果可以看出,抛出InterruptedException的线程SleepThread,其中断标识位被清除了,而一直忙碌运作的线程BusyThread,中断标识位没有被清除。

    4、使用中断来终止线程

           下面的例子代码,使用了中断机制来终止一个线程。

            

        package com.baowei.threadinter;
         
        public class ThreadStopSafeInterrupted {
            public static void main(String[] args) throws InterruptedException {
                Thread thread = new Thread() {
                    @Override
                    public void run() {
                        while (true) {
                            // 使用中断机制,来终止线程
                            if (Thread.currentThread().isInterrupted()) {
                                System.out.println("Interrupted ...");
                                break;
                            }
         
                            try {
                                Thread.sleep(3000);
                            } catch (InterruptedException e) {
                                System.out.println("Interrupted When Sleep ...");
                                // Thread.sleep()方法由于中断抛出异常。
                                // Java虚拟机会先将该线程的中断标识位清除,然后抛出InterruptedException,
                                // 因为在发生InterruptedException异常的时候,会清除中断标记
                                // 如果不加处理,那么下一次循环开始的时候,就无法捕获这个异常。
                                // 故在异常处理中,再次设置中断标记位
                                Thread.currentThread().interrupt();
                            }
         
                        }
                    }
                };
         
                // 开启线程
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
         
            }
         
        }

           程序的运行结果

        Interrupted When Sleep ...
        Interrupted ...


    5、关于终止线程的选择

           感觉使用boolean类型的变量,实现起来比较简单。还不会引起数据的不正确问题。

          

    6、参考的书籍

    Java高并发程序设计

    Java并发编程的艺术

  • 相关阅读:
    生产上第一使用线程池后的总结与反思
    20190407
    20190403
    Asp.net MVC中的ViewData与ViewBag
    easyui datagrid分页
    EF从数据库更新模型更新不到新表
    C语言 笔记(函数)
    python 写100~1000以内水仙花数
    python 求前n项阶乘的和
    python 写九九乘法表
  • 原文地址:https://www.cnblogs.com/CreatorKou/p/9829927.html
Copyright © 2020-2023  润新知