java 基础线程(3)如何停止线程

停止线程

停止线程的方法有:
- 1.run() 方法执行完
- 2.线程对象调用stop() 方法
- 3.线程对象调用 interrupt()方法
- 4.使用共享变量 volatile

run()方法执行完,没什么说的, 线程调用stop(),这个方法已经被废弃(不建议使用)
原因:

-1. 即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。

-2. 释放该线程所持有的所有的锁

主要是第二点,释放该线程所持有的所有的锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放,那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。

来源:link

先来一个简单的常用的安全的停止线程的方法

public class ThreadSafeMethodOne extends Thread {

    /*volatile 保证 多个线程对同一变量的共享,
    通俗点来说就是 保证任何一个线程在读取 volatile 修饰的域 的时候,都将看到的是最新修改的值
    */
    public volatile  boolean  isExit = false;
    @Override
    public void run() {
        super.run();
        while (!isExit){
            // todo
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程退出了");
    }
}
测试方法:
public void testSafeOne(){
    ThreadSafeMethodOne methodOne = new ThreadSafeMethodOne();
    methodOne.start();

    try {
        Thread.sleep(300);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    methodOne.isExit = true;
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

结果:

线程退出了
 这里注意一点,如果主线程执行时间短,是不会看到这行字的打印的

再用interrupt()的方法
这个方法不是说 执行就立马停止线程,他只是设置了一个停止标识,系统看到这个标识,才会停止线程

public class ThreadSafeMethodTwo extends Thread {
    @Override
    public void run() {
        super.run();

        // while (!Thread.interrupted()) 和 isInterrupted() 
        //一样都是判断线程是否处于中断(设置的标识的)状态
        // 这里有两种状况
        // 一种是在非阻塞的情况下,也就是说当 在主线程中去用 interrupt() 方法停止
        // 线程的时候,用isInterrupted()会为true,线程会退出循环
        // 还有一种是在阻塞的情况下,当调用线程的interrupt()方法时,如使用了sleep,
        // 同步锁的wait,socket中的receiver,accept等方法时,使线程处于阻塞状态
        // 会使线程先清掉中断标识(isInterrupted()  = false 或者 
        //Thread.interrupted() = false)并且抛出InterruptException异常 ,
        // 这个时候就会有两种处理模式 ,一种是直接用break 如下
        while (!isInterrupted()){

            System.out.println("isInterrupted  "+  isInterrupted());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("线程阻塞者,强制退出了");
                break;
            }
        }
    }
}
测试方法:
    public void testTwo(){
        ThreadSafeMethodTwo methodTwo = new ThreadSafeMethodTwo();
        methodTwo.start();
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        methodTwo.interrupt();
    }
结果:

isInterrupted  false

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.cxl.thread.ThreadSafeMethodTwo.run(ThreadSafeMethodTwo.java:25)
线程阻塞者,强制退出了

显示异常是因为 e.printStackTrace();

还有一种解决思路

public class ThreadSafeMethodThree extends Thread {
    @Override
    public void run() {
        super.run();
        // while (!Thread.interrupted()) 和 isInterrupted() 一样都是判断线程是
        //否处于中断(设置的标识的)状态
        // 这里有两种状况
        // 一种是在非阻塞的情况下,也就是说当 在主线程中去用 interrupt() 方法停止
        //线程的时候,用isInterrupted()会为true,线程会退出循环
        // 还有一种是在阻塞的情况下,当调用线程的interrupt()方法时,如使用了sleep,
        //同步锁的wait,socket中的receiver,accept等方法时,使线程处于阻塞状态
        // 会使线程先清掉中断标识(isInterrupted()  = false 或者 
        //Thread.interrupted() = false)并且抛出InterruptException异常 ,
        // 这个时候就会有两种处理模式 这种处理模式的思路是 
        //在 catch 中重新设置中断标识  也就是说 Thread.interrupted()  = true
        // 重新设置为中断状态,
        while (!Thread.interrupted()){
            System.out.println("线程的当前的中断状态是 false ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
               e.printStackTrace();
                System.out.println("因为 sleep 阻塞 所以抛出了异常,并且我们要给他重
                //新 给一个 中断状态 true ");
                Thread.currentThread().interrupt();
                System.out.println("线程的当前在 Thread.currentThread().interrupt(); 之后的的中断状态是 "+ isInterrupted());
            }
        }
        System.out.println("线程退出了");
    }
}
 测试方法 和上面一样

 结果:

 线程的当前的中断状态是 false 
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.cxl.thread.ThreadSafeMethodThree.run(ThreadSafeMethodThree.java:24)
因为 sleep 阻塞 所以抛出了异常,并且我们要给他重新 给一个 中断状态 true 
线程的当前在 Thread.currentThread().interrupt(); 之后的的中断状态是 true
线程退出了

总结一下: 用volatile 设置停止标识,优点是结构简单,但是当 子线程阻塞 时,主线程结束的早,我们是不知道子线程是否结束了的,
下面的两种的思路其实差不多,不过选择上,break 更来的直接一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值