Java怎么终止线程呢?

本文介绍了四种Java线程安全终止的方法:1) 线程体执行完成;2) 不推荐使用的`Thread.stop`方法及其风险;3) 使用退出标志,推荐使用`volatile`关键字确保可见性;4) 使用`Thread.interrupt`方法,注意对阻塞状态和非阻塞状态的处理。强调了避免使用`Thread.stop`以防止数据不一致和资源泄露,推荐使用安全的退出策略。
摘要由CSDN通过智能技术生成

方法一、程序正常运行结束

线程体执行完成了,那么线程也就自动结束了。

方法二、使用stop方法

这是一个被弃用的方法,打开Thread类可以看到它是被@Deprecated注解修饰的,非常不推荐使用这个方法

@Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // The VM can handle all thread states
        stop0(new ThreadDeath());
    }

在程序中直接使用Thread.stop方法强行终止线程,是很危险的,就像突然关闭计算机的电源,而不是正常关机,可能会产生不可预料的后果。

在程序中使用Thread.stop方法终止线程时,该线程的子线程会抛出ThreadDeatherror错误,并且释放子线程持有的所有的锁

加锁的代码块一般用于保护数据的一致性,如果在调用Thread.stop方法后导致该线程所持有的所有锁突然释放而使锁资源不可控制,被保护的数据就可能出现不一致的情况,其他线程在使用这些被破坏的数据时,有可能使程序运行错误。

测试看看:

public class TerminateThread implements Runnable {
    @Override
    public void run() {
        int i = 0;
        while(true) {
            System.out.println("i:" + (i++));
        }
    }
    public void startThread() {
        Thread thread = new Thread(new TerminateThread());
        thread.start();
        for(int i = 0; i <= 10; i++) {
            if(i == 9) {
                thread.stop();//调用stop方法
                System.out.println("线程终止");
                break;
            }
            System.out.println("main-->" + i);
        }
    }

    public static void main(String[] args) {
        TerminateThread t = new TerminateThread();
        t.startThread();
    }
}

输出结果:

main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
i:0
main-->6
main-->7
main-->8
i:1i:1线程终止

可以看到最后i= 1输出了两遍

方法三、使用退出标志

用一个变量来判断线程是否结束

/**
 * 终止线程
 * 1、 线程执行完毕
 * 2、 外部标志位(不要使用stop、destroy,不安全)
 */
public class TerminateThread  {
    //加入标识,标记线程体是否可以运行
    private static boolean flag = true;//
    public void terminate() {
        this.flag = false;
    }
    public static void main(String[] args) {
        TerminateThread tt = new TerminateThread();
        new Thread(() -> {
            int i = 0;
            while(flag) {
                System.out.println("i:" + (i++));
            }
        }).start();
        for(int i = 0; i <= 10; i++) {
            if(i == 9) {
                tt.terminate();
                System.out.println("线程终止");
                break;
            }
            System.out.println("main-->" + i);
        }
    }
}

输出结果:

main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
i:0
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
main-->7
main-->8
i:10
线程终止

使用volatile关键字来修饰标志符更佳

public class TerminateThread  {
    //加入标识,标记线程体是否可以运行
//    private static boolean flag = true;//
//    public void terminate() {
//        this.flag = false;
//    }
    static volatile boolean flag = true;
    public static void main(String[] args) {
        TerminateThread tt = new TerminateThread();
        new Thread(() -> {
            int i = 0;
            while(flag) {
                System.out.println("i:" + (i++));
            }
        }).start();
        for(int i = 0; i <= 10; i++) {
            if(i == 9) {
                flag = false;
                System.out.println("线程终止");
                break;
            }
            System.out.println("main-->" + i);
        }
    }
}

输出结果:

main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
i:0
i:1
i:2
i:3
i:4
i:5
i:6
main-->7
main-->8
线程终止
i:7

方法四、使用Interrupt

当其他线程通过调用当前线程的interrupt方法,表示向当前线程打个招呼,告诉它可以中断线程的执行了,至于什么时候中断,取决于当前线程自己。

Thread.interrupted()对设置中断标识的线程复位,并返回当前的中断状态。
写个小demo看看:

public class TerminateThread {
    private static int i;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("before:" + Thread.currentThread().isInterrupted());
                    Thread.interrupted();//对中断标识复位
                    System.out.println("after:" + Thread.currentThread().isInterrupted());
                }
            }
        });
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();//中断
    }
}

输出:

before:true
after:false

使用interrupt方法终止线程有两种情况:

  • 线程处于阻塞状态。例如,在使用sleep、调用锁的wait或者调用socket的receiver、accept方法时,会使线程处于阻塞状态。在调用线程的interrupt方法时,会抛出InterruptException异常,然后通过break跳出状态检测循环,可以有机会结束这个线程的执行。通常会以为只要调用interrupt方法就会结束线程,这是不对的,一定要先捕获InterruptException异常再通过break跳出循环,才能正常结束run方法。
public class TerminateThread {
    private static int i;
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            //线程处于阻塞状态下,中断是有效的
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                //抛出异常来响应中断请求
                e.printStackTrace();
            }
        });
        thread.start();
        thread.interrupt();
    }
}
  • 线程未处于阻塞状态。此时,使用isInterrupted方法判断线程的中断标志来退出循环。在调用interrupt方法时,中断标志会被设置为true,并不能立刻退出线程,而是执行线程终止前的资源释放操作,等待资源释放完毕后退出该线程。
public class TerminateThread {
    private static int i;
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            //Thread.currentThread().isInterrupted()默认是false
            while (!Thread.currentThread().isInterrupted())//判断中断标识
                i++;
        });
        thread.start();
        //interrupt这个属性由false变成true
        thread.interrupt();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值