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. 【C#进阶】多播委托和委托数组像是一回事~

    这个MathOperation类有三静态方法,参数都是double,并且没有返回值,考虑用Action<>() 这种预定义的委托哦 class MathOperations { publi ...

  2. 漫谈java重载与重写

    重载(Overloading):为了让方法名相同而形参不同的构造方法同时存在,让类以统一的方式处理不同类型数据的一种手段 重写(Overriding):导出类对继承自基类的方法做出一定的修改,又称方法 ...

  3. 界面使用webview,并且webview里面有图片进行自动切换导致界面上滚动条卡顿。

    最近的项目是用webview做的界面,但是在界面顶端加了android本地动画效果的横向滚动条.当webview里面的图片切换时导致滚动条动画卡顿. 1:setLayerType(View.LAYER ...

  4. jQuery ajax的traditional参数的作用///////////////////////////////////zzzzzzzzzzz

    jQuery ajax的traditional参数的作用 i33 发布时间: 2013/04/03 10:05 阅读: 9859 收藏: 9 点赞: 1 评论: 0 一般的,可能有些人在一个参数有多个 ...

  5. 关于DoesObjectExist

    目录: 我们可以看到这个文件夹目录是存在的 文件: 然后,我们运行测试一下: 文件存在检测成功(正常) 文件夹存在,但检测失败! ??? 明明存在的,为什么检测不到……

  6. SQL语句 在一个表中插入新字段

    SQL语句 在一个表中插入新字段: alter table 表名 add 字段名 字段类型 例: alter table OpenCourses add Audio varchar(50)alter ...

  7. select in 在postgresql的效率问题

    在知乎上看到这样一个问题: MySQL 查询 select * from table where id in (几百或几千个 id) 如何提高效率?修改 电商网站,一个商品属性表,几十万条记录,80M ...

  8. 如何写一个HttpClient[1]——URI的处理

    如何写一个HttpClient[1]--URI的处理 在翻阅apache的http client的代码的时候,看到org.apache.http.client.utils.URIBuilder.jav ...

  9. maven nexus 私服的搭建学习

    之前对maven有过初步的了解与认识,自己也创建过项目使用其来管理,但都是非常粗浅的操作,今天在高人的指点下,也学着在自己的电脑上搭建一个maven私服,虽然技术难度也不高,但为了更深层次的提高,这些 ...

  10. QT 中文显示问题

    在QT4 中,要显示中文,都是要这样写: #include <QTextCodec> QTextCodec::setCodecForTr(QTextCodec::codecForLocal ...