多线程之interrupt与优雅停止一个线程


1.背景

在实际开发中,我们可能会遇到终端某个线程的场景,

比如不断扫描数据库的发货订单时,这时候需停止扫描,

当然我们不能把程序关了,我们只希望停止扫描数据库这一个线程,

那么应该怎么办了?

这就可以使用线程中提供的interrupt()这个方法

2.案例演示

package com.ldp.demo01;

import com.common.MyThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

/**
 * @author 姿势帝-博客园
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 01/16 9:41
 * @description 

* interrupt()方法的理解 * 1.只是给线程设置一个打断标记,不会改变线程的实际状态 * 2.打断睡眠中的线程会清除打断标记(即标记无效) * 3.实际应用中可以利用判断线程的打断标记,来判断是否继续业务. *

*/ @Slf4j public class Test03Interrupt { /** * 打断正常的线程 * 1. t1.interrupt() 只是给线程设置一个打断标记,不会改变线程的实际状态 */ @Test public void test01() { Thread t1 = new Thread(() -> { log.info("执行中......"); while (true) { } }, "t1"); // 启动线程 t1.start(); // 查看打断状态 log.info("interrupted=" + t1.isInterrupted()); // 查看线程状态 log.info("线程状态为:" + t1.getState()); // 睡眠2秒 MyThreadUtil.sleep(2); // 打断线程 t1.interrupt(); // 查看打断状态 log.info("interrupted=" + t1.isInterrupted()); // 再次查看线程状态 log.info("线程状态为:" + t1.getState()); // 防止主线程结束 MyThreadUtil.sleep(10); } /** * 打断处于睡眠的线程 * 1. 打断睡眠中的线程会清除打断标记(即标记无效) */ @Test public void test02() { Thread t1 = new Thread(() -> { while (true) { log.info("执行中......"); Thread currentThread = Thread.currentThread(); if (currentThread.isInterrupted()) { log.info("isInterrupted=true"); break; } try { Thread.sleep(50 * 1000); } catch (InterruptedException e) { e.printStackTrace(); log.info("isInterrupted=" + currentThread.isInterrupted()); // 重新设置打断标记 currentThread.interrupt(); } } }, "t1"); // 启动线程 t1.start(); // 睡眠2秒 MyThreadUtil.sleep(2); // 打断线程 t1.interrupt(); // 查看打断状态 log.info("isInterrupted=>" + t1.isInterrupted()); // 防止主线程结束 MyThreadUtil.sleep(10); } /** * 两阶段终止 * 案例: * 假设有一个主线程一直在扫描数据的订单进行发货操作, * 在页面有我们需要有暂停发货\继续发货\停止发货三个功能 */ @Test public void test03() { // 扫描数据线程 Thread threadDataMain = new Thread(() -> { Thread currentThread = Thread.currentThread(); while (true) { boolean interrupted = currentThread.isInterrupted(); if (interrupted) { // 如果线程被打断就停止循环 log.info("停止获取数据"); break; } // 模拟读取数据数据,每次1条 String order = getOrder(); if (order == null) { log.info("无数据休息2秒"); // 数据库无订单休息2秒 try { Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printStackTrace(); // 重新设置打断标记 currentThread.interrupt(); } continue; } // 发货线程 Thread threadOrder = new Thread(() -> { log.info("订单发货中:" + order); }, "t-" + order); threadOrder.start(); } }, "thread-数据库扫描主线程"); threadDataMain.start(); // 模拟发货10秒后停止发货 MyThreadUtil.sleep(10); threadDataMain.interrupt(); // 防止主线程结束 MyThreadUtil.sleep(20); } /** * 模拟数据库获取订单 * * @return */ public String getOrder() { // 模拟有时候无数据的情况 // int nextInt = new Random().nextInt(10); long millis = System.currentTimeMillis(); if (millis % 3 > 0) { return null; } // 3的整数倍才返回订单 return "NO" + System.currentTimeMillis(); } }

完美!