优雅停止Thread(线程)的3种方式

22 篇文章 3 订阅

咱们都知道Java中实现线程的两种方式:继承Thread或者实现Runnable。不管是哪种方式最后都是操作的Thread类。本篇文章我们聊的就是正常活动中的Thread怎么停止,虽然Thread类提供了stop()方法,但是这种方法太暴力,不安全所以被弃用了。

为什么说stop()太暴力呢?我这里举个例子:一个餐厅是禁止抽烟的,但是一位男士进入餐厅掏出烟就抽,服务员发现后立马强制掐断男士手中的烟,大家可以想象后果是什么。这种方式就相当于将正在活动的Thread强制stop一样,太暴力。那服务员应该怎么做呢?

服务员是不是应该礼貌的告知抽香烟的男士:先生您好,我们餐厅是禁止抽烟的。如果男士明事理那就会掐断香烟,如果不明事理是不是就不会掐断香烟继续抽呀。这种协商机制导致的后果就是抽香烟的男士可能掐断香烟,也可能不会掐断香烟。Thread停止的方式也是类似,需要协商,假如t2线程想让t1线程停止,只能通知t1停止,但是t1是否停止只能看t1自己是否愿意停止了,咱们看看停止线程的三种方式。

1、通过volatile修饰的标识停止线程

volatile是Java中的关键字,用来修饰会被不同线程访问和修改的变量。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。
可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。volatile即可实现线程之间的可见性。

实例代码:

package com.lc.test01;

import java.util.concurrent.TimeUnit;

/**
 * @author liuchao
 * @date 2023/4/8
 */
public class StopThreadOne {
    volatile static Boolean stopFlag = Boolean.FALSE;

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            while (true) {
                if (stopFlag) {
                    System.out.println(Thread.currentThread().getName() + ",线程被终止");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + ",线程进行中");
            }
        }, "t1");
        t1.start();

        try {
            TimeUnit.MILLISECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            stopFlag = Boolean.TRUE;
            System.out.println("---已发出通知,告知t1线程停止");
        }, "t2").start();
    }
}

效果:

t1,线程进行中
t1,线程进行中
...

...
t1,线程进行中
---已发出通知,告知t1线程停止
t1,线程被终止 

2、通过CAS中的AtomicBoolean 标识停止线程

CAS 全称是 compare and swap,是一种用于在多线程环境下实现同步功能的机制。CAS 操作包含三个操作数 -- 内存位置、预期数值和新值。CAS 的实现逻辑是将内存位置处的数值与预期数值想比较,若相等,则将内存位置处的值替换为新值。若不相等,则不做任何操作。这种原子操作也可以保证写线程改变数据后,读线程立马能读取到改变后的数据。

实例:

package com.lc.test01;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author liuchao
 * @date 2023/4/8
 */
public class StopThreadTwo {
    static AtomicBoolean stopFlag = new AtomicBoolean(Boolean.FALSE);

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            while (true) {
                if (stopFlag.get()) {
                    System.out.println(Thread.currentThread().getName() + ",线程被终止");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + ",线程进行中");
            }
        }, "t1");
        t1.start();

        try {
            TimeUnit.MILLISECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            stopFlag.set(Boolean.TRUE);
            System.out.println("---已发出通知,告知t1线程停止");
        }, "t2").start();
    }
}

效果: 

t1,线程进行中
t1,线程进行中
...

...
t1,线程进行中
---已发出通知,告知t1线程停止
t1,线程被终止 

3、通过interrupt、isInterrupted方法配合停止线程

interrupt、isInterrupted两个方法都是Thread自带的api。

interrupt()是将一个线程的中断标识设置为true,通俗说就是告诉这个线程你需要中断。

isInterrupted()是判断线程的中断标识是否被设置为true

那使用的原理就是,t2线程将t1线程中断标识设置为true,t1线程判断中断标识是否为true,但是t1是否停止取决于t1自己是否想停止。

实例代码:

package com.lc.test01;

import java.util.concurrent.TimeUnit;

/**
 * @author liuchao
 * @date 2023/4/8
 */
public class StopThreadThree {

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println(Thread.currentThread().getName() + ",线程被终止");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + ",线程进行中");
            }
        }, "t1");
        t1.start();

        try {
            TimeUnit.MILLISECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            t1.interrupt();
            System.out.println("---已发出通知,告知t1线程停止");
        }, "t2").start();
    }
}

效果:

t1,线程进行中
t1,线程进行中
...

...
t1,线程进行中
---已发出通知,告知t1线程停止
t1,线程被终止 

这种方式使用时,有个地方需要注意:

如果t1线程内部阻塞的调用wait() 、wait(long)或wait(long, int)方法,或者在join() , join(long) , join(long, int) , sleep(long) ,或sleep(long, int) ,那么它的中断状态将被清除,并且将收到一个InterruptedException 。需要在catch中重新将中断标识设置为true

package com.lc.test01;

import java.util.concurrent.TimeUnit;

/**
 * @author liuchao
 * @date 2023/4/8
 */
public class StopThreadThree {

    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println(Thread.currentThread().getName() + ",线程被终止");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + ",线程进行中");

                try {
                    TimeUnit.MILLISECONDS.sleep(5);
                } catch (InterruptedException e) {
                    System.out.println("抛出异常" + e.getMessage());
                    //注意这里一定要重新将中断标识设置为true
                    Thread.currentThread().interrupt();
                }
            }
        }, "t1");
        t1.start();

        try {
            TimeUnit.MILLISECONDS.sleep(30);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            t1.interrupt();
            System.out.println("---已发出通知,告知t1线程停止");
        }, "t2").start();
    }
}

4、总结

 不管是那种方式停止线程,都是以协商而不是暴力,t2线程告知t1线程中断,t1是不会里面停止的,最终t1是否停止取决于t1是否做了中断判断。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Python中,有几种方法可以停止线程。一种常见的方法是使用状态变量来控制线程的循环体,当状态变量为False时,线程退出循环并停止运行。另一种方法是使用全局变量作为状态变量,在主线程中修改全局变量的值来控制线程的停止。还可以使用threading.Event对象作为信号来停止线程。以下是这些方法的示例代码: 方法一: 使用状态变量停止线程 ```python import threading import time class Job(threading.Thread): def __init__(self, *args, **kwargs): super(Job, self).__init__(*args, **kwargs) self.__flag = threading.Event() # 用于暂停线程的标识 self.__flag.set() # 设置为True self.__running = threading.Event() # 用于停止线程的标识 self.__running.set() # 将running设置为True def run(self): while self.__running.isSet(): self.__flag.wait() # 为True时立即返回, 为False时阻塞直到self.__flag为True后返回 print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) time.sleep(1) def pause(self): self.__flag.clear() # 设置为False, 让线程阻塞 def resume(self): self.__flag.set() # 设置为True, 让线停止阻塞 def stop(self): self.__flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话 self.__running.clear() # 设置为False a = Job() a.start() time.sleep(3) a.pause() time.sleep(3) a.resume() # time.sleep(2) # a.stop() ``` 方法二: 使用全局变量停止线程 ```python import threading import time stop_threads = False def run(): while True: print('thread running') global stop_threads if stop_threads: break stop_threads = False t1 = threading.Thread(target=run) t1.start() time.sleep(1) stop_threads = True t1.join() print('thread killed') ``` 方法三: 使用threading.Event对象停止线程 ```python import threading import time def run(): while True: print('thread running') if stop_event.is_set(): break stop_event = threading.Event() stop_event.clear() t1 = threading.Thread(target=run) t1.start() time.sleep(1) stop_event.set() t1.join() print('thread killed') ``` 这些方法可以根据具体的需求选择使用,根据需要来选择合适的方法来停止线程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Python中线程的使用(停止操作)](https://blog.csdn.net/leishupei/article/details/114640480)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [python多线程编程:如何优雅地关闭线程](https://blog.csdn.net/captain5339/article/details/128360804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈行动派

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值