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. Andorid项目创建AVD时,OK按钮无法点亮

    经上网查证,发现原因在于CPU/ABI选项无法选择,并显示“No system images installed for this target”,也就是没有适合的系统镜像,通过与安装好了的ADT-b ...

  2. Java 高精度数字

    BigInteger // 高精度整数 BigDecimal //高精度小数  小数位数不受限制

  3. 2.6 C#的数据转换

    C#有多种数据类型,每种数据类型只能存储这种类型的变量,但又的时候我们需要各种类型之间的转换.比如在计算2+3.5的时候,这个时候有两种情况: 自动类型转换:2种不同类型的数据运算,低精度类型的数值会 ...

  4. ListView遍历每个Item出现NullPointerException的异常

    在使用ListView过程中我们有时候需要遍历取得每个Item项中的一些数据(比如每个Item里面有TextView,需要获取它的文本等等),但是我们在遍历过程中经常会遇到NullPointerExc ...

  5. Linux下的SVN服务器搭建

    鉴于在搭建时,参考网上很多资料,网上资料在有用的同时,也坑了很多人 本文的目的,也就是想让后继之人在搭建svn服务器时不再犯错,不再被网上漫天的坑爹作品所坑害,故此总结 /******开始****** ...

  6. JSON对象长度和遍历方法

    摘自博客 (http://caibaojian.com/json-length.html) 原文链接:http://caibaojian.com/json-length.html JSON数组有长度j ...

  7. module not exists: xxxx Error in ThinkPHP

    Introduction ThinkPHP is a very charming PHP framework to easily build a website. It's structured in ...

  8. java 线程返回值

    1.传统方式需要新建一个接口类,然后在接口类中将结果在方法中作为参数进行处理 package de.bvb.test3; public class Test3 { public static void ...

  9. [转] dpkg-deb命令

    点击此处阅读原文 function addLink() { var body_element = document.getElementsByTagName('body')[0]; var selec ...

  10. java中常见的几种异常

    算术异常类:ArithmeticExecption空指针异常类:NullPointerException类型强制转换异常:ClassCastException数组负下标异常:NegativeArray ...