stop() 存在的问题

使用 stop() 来退出线程是不安全的。它会解除由线程获取的所有锁,可能导致数据不一致。

举个例子:

public class StopTest {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        person.setNameAndAge("Tom", 10);
        MyThread thread = new MyThread(person);
        thread.start();
        Thread.sleep(500);
        thread.stop();
        System.out.println(person.toString());
    }
}

class MyThread extends Thread {
    Person person;

    public MyThread(Person person) {
        this.person = person;
    }

    @Override
    public void run() {
        person.setNameAndAge("Lin", 20);
    }
}

class Person{
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    synchronized public void setNameAndAge(String name,int age){
        this.name = name;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.age = age;
    }

    @Override
    public String toString() {
        return getName() + "," + getAge();
    }
}

打印输出:

Lin,10

按理说,setNameAndAge() 是一个同步方法,对象 person 总能保证对 name 和 age 同时赋值。因此上例中我们期待的输出应该是 “Lin,20”,由于调用的是 stop(),它会马上释放锁(即使正在同步块中),使得数据不一致。

所以要停止或退出线程,请忘记 stop()。

interrupt() 能退出线程吗?

public class InterruptTest {
    public static void main(String[] args) throws Exception {
        MyThread thread = new MyThread();
        thread.start();
        Thread.sleep(100);
        thread.interrupt();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter("C:/log.txt"));
            for (int i = 0; i < 5000000; i++) {
                String str = "";
                if (i == 1) {
                    str = i + "";
                } else {
                    str = "\n" + i;
                }
                writer.write(str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

可以看到输出的文件总行数为 500000,说明 interrupt() 并没有马上终止循环。

interrupt() 仅仅是在当前线程打了一个停止标记,并没有真的停止线程。

异常法退出线程

上代码:

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

class MyThread extends Thread {
    @Override
    public void run(){
        boolean flag = true;
        while (flag) {
            if (this.isInterrupted()) {
                System.out.println("线程即将停止");
                try {
                    throw new InterruptedException();
                } catch (InterruptedException e) {
                    flag = false;
                }

            }
        }
        System.out.println("已经跳出循环,线程停止");
    }
}

打印输出:

线程即将停止
已经跳出循环,线程停止

run 方法执行完,线程自然就结束了。

使用 return 退出线程

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

class MyThread2 extends Thread {
    @Override
    public void run() {
        while (true) {
            if (this.isInterrupted()) {
                System.out.println("线程停止");
                return;
            }
        }
    }
}

打印输出:

线程停止

Java - 安全的退出线程的更多相关文章

  1. Java线程监听,意外退出线程后自动重启

    Java线程监听,意外退出线程后自动重启 某日,天朗气清,回公司,未到9点,刷微博,顿觉问题泛滥,惊恐万分! 前一天写了一个微博爬行程序,主要工作原理就是每隔2分钟爬行一次微博,获取某N个关注朋友微博 ...

  2. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  3. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  4. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  5. Java多线程-新特性-线程池

    Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...

  6. Java笔记(二十)……线程间通信

    概述 当需要多线程配合完成一项任务时,往往需要用到线程间通信,以确保任务的稳步快速运行 相关语句 wait():挂起线程,释放锁,相当于自动放弃了执行权限 notify():唤醒wait等待队列里的第 ...

  7. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  8. Java并发编程:线程池的使用(转)

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  9. 初步探究java中程序退出、GC垃圾回收时,socket tcp连接的行为

    初步探究java中程序退出.GC垃圾回收时,socket tcp连接的行为 今天在项目开发中需要用到socket tcp连接相关(作为tcp客户端),在思考中发觉需要理清socket主动.被动关闭时发 ...

随机推荐

  1. RDIFramework.NET平台代码生成器V3.1版本全新发布-更新于2016-10-29(提供下载)

    本次主要更新内容: 1.增加对Oracle表创建语句的查看. 2.新增对MySql的代码生成支持. 3.全面重构对多线程的支持,改变以前会无故退出的现象. RDIFramework.NET代码生成器V ...

  2. SLP的模块结构

    SLP的模块结构 在开发初期,拟将SLP分为5个模块: 基础练习模块 特定歌曲难点练习模块 玩家能力测试模块 全局设置模块 玩家信息模块 基础练习模块 这里提供可控类型.可控长度.可控BPM的练习套餐 ...

  3. github android

    作者:ruijun 链接:https://www.zhihu.com/question/37160415/answer/79569042 来源:知乎 著作权归作者所有,转载请联系作者获得授权. ### ...

  4. Python中递归的最大次数

    实际应用中遇到了一个python递归调用的问题,报错如下: RuntimeError: maximum recursion depth exceeded while calling a Python ...

  5. 纯css的防止图片撑破页面的代码(图片自动缩放)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. 存储过程中的output跟return区别及实例说明

    存储过程return,表示该存储过程执行到当当前return位置,不再向下执行: 存储过程写法:set ANSI_NULLS ON set QUOTED_IDENTIFIER ON GO ALTER ...

  7. dll 日志文件 放在同一个目录。

    string strPath = "log.txt"; 如果日志问价跟dll文件放在一起,直接这么些就可以了.

  8. C语言回顾-指针

    1.指针:地址 指针变量:存放指针的变量 指针变量的定义:数据类型 *指针变量名 或者 数据类型* 指针变量名 指针变量的初始化:int *p=&a;int *p=NULL;(不能先定义后初始 ...

  9. oracle中scn(系统改变号)

    系统scn:                 select checkpoint_change# from v$database; 文件scn:                 select name ...

  10. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...