并发编程之【优雅地结束线程的执行】

目录

Thread类中的stop方法【不推荐】

查看源码

测试

不推荐使用的原因

使用标志位的判断来结束线程的执行【不推荐】

实现案例

不推荐使用的原因

通过对线程对象的封装来停止线程的执行【推荐】

实现思路

具体实现

测试

案例一:任务未超时

案例二:任务执行超时


Thread类中的stop方法【不推荐】

查看源码

通过源码可以看到stop()方法会强制线程停止运行

java 复制代码
package java.lang;

// ...

public
class Thread implements Runnable {
    // ...
    
    // Forces the thread to stop executing.
    @Deprecated
    public final void stop() {
        // ...

        stop0(new ThreadDeath());
    }

    // ...
}

测试

java 复制代码
package concurrency;

public class ThreadStopTest {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {

            }
        });
        t.start();

        // 1秒后查看t线程是否为活跃状态
        sleepTime(1_000);
        System.out.println("t线程是否活跃:" + t.isAlive());

        // 3秒后强制t线程停止运行
        long beginTime = System.currentTimeMillis();
        sleepTime(3_000);
        t.stop();
        while (true) {
            if (!t.isAlive()) {
                long endTime = System.currentTimeMillis();
                System.out.println((endTime - beginTime) + "ms");
                break;
            }
        }
    }

    public static void sleepTime(long time) {
        if (time <= 0) return;
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

不推荐使用的原因

  • 方法已废弃,不建议使用
  • 方法本身不安全

使用标志位的判断来结束线程的执行【不推荐】

实现案例

java 复制代码
package concurrency;

public class FlagTest {
    private volatile static boolean flag = true;

    public static void main(String[] args) {
        new Thread(() -> {
            while (flag) {

            }
        }).start();

        // 3秒后,通过改变flag标识来停止线程t
        try {
            Thread.sleep(3_000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        flag = false;
    }
}

不推荐使用的原因

  • 在很多场景下并没有机会去判断标志位(如任务长时间阻塞等待)

通过对线程对象的封装来停止线程的执行【推荐】

实现思路

  • 封装一个类,提供两个方法,分别为执行任务的方法和超时停止任务执行的方法
  • 通过daemon和interrupt来实现

具体实现

java 复制代码
package concurrency;

public class ThreadService {
    private Thread executeThread;

    private volatile boolean isFinish = false;

    /**
     * 执行任务
     */
    public void execute(Runnable task) {
        if (task == null) return;
        executeThread = new Thread(() -> {
            Thread t = new Thread(task);
            // 设置为守护线程
            t.setDaemon(true);
            t.start();
            try {
                // task执行完
                t.join();
                isFinish = true;
            } catch (InterruptedException e) {
                System.out.println("任务执行超时...");
            }
        });
        executeThread.start();
    }

    /**
     * 超时停止任务的执行
     */
    public void shutdown(long timeout) {
        if (timeout <= 0) return;
        long currentTime = System.currentTimeMillis();
        while (!isFinish) {
            // 超时,打断执行任务的线程,使其结束
            if (System.currentTimeMillis() - currentTime > timeout) {
                executeThread.interrupt();
                break;
            }

            // 减少空转次数
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
            }
        }
    }
}

测试

案例一:任务未超时

java 复制代码
package concurrency;

public class ThreadServiceTest {
    public static void main(String[] args) {
        // 任务:从数据库中查询数据
        Runnable queryDataFromDB = () -> {
            try {
                // 这里该任务执行耗时10s
                Thread.sleep(10_000);
                System.out.println("queryDataFromDB task execute success!");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };

        // 执行任务
        ThreadService threadService = new ThreadService();
        long beginTime = System.currentTimeMillis();
        threadService.execute(queryDataFromDB);
        // 最大忍耐限度为20s,任务没有超过20s就按照实际耗时执行成功
        threadService.shutdown(20_000);
        long endTime = System.currentTimeMillis();
        System.out.println("总耗时:" + (endTime - beginTime) + "ms");
    }
}

案例二:任务执行超时

java 复制代码
package concurrency;

public class ThreadServiceTest {
    public static void main(String[] args) {
        // 任务:从数据库中查询数据
        Runnable queryDataFromDB = () -> {
            try {
                // 这里该任务执行耗时30s
                Thread.sleep(30_000);
                System.out.println("queryDataFromDB task execute success!");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };

        // 执行任务
        ThreadService threadService = new ThreadService();
        long beginTime = System.currentTimeMillis();
        threadService.execute(queryDataFromDB);
        // 最大忍耐限度为20s,如果任务执行超过20s则认为任务失败,停止任务
        threadService.shutdown(20_000);
        long endTime = System.currentTimeMillis();
        System.out.println("总耗时:" + (endTime - beginTime) + "ms");
    }
}
相关推荐
市场部需要一个软件开发岗位1 小时前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
忆~遂愿2 小时前
GE 引擎进阶:依赖图的原子性管理与异构算子协作调度
java·开发语言·人工智能
MZ_ZXD0012 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
PP东2 小时前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
ManThink Technology2 小时前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
invicinble2 小时前
springboot的核心实现机制原理
java·spring boot·后端
人道领域2 小时前
SSM框架从入门到入土(AOP面向切面编程)
java·开发语言
大模型玩家七七2 小时前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
CodeToGym3 小时前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel