ThreadPoolExecutor 线程执行超时,释放线程
如果线程中的执行时间过长,导致长时间被占用,可以通过新建一个子线程,来监控主线程的执行超时时间,如果超时了,通过子线程杀掉父线程 (主意,父线程被杀后,子线程还会活着) 子线程杀掉主线程
这个问题其实还是没有搞定。下面的代码只是发起了线程的中断,某一行代码执行结束后,不会执行后续的代码。但就这某一行卡住了的话,本方案还是无解的。
package com.vipsoft.Thread; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger; public class ThreadPoolExecutorTest { public static void main(String[] args) throws Exception {
int corePoolSize = 2;
int maximumPoolSize = 5;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(3); //定义一个大小为2的队列,只等有一个任务在排队等,多出来的需要开新线程
ThreadFactory threadFactory = new MyTreadFactory();
RejectedExecutionHandler handler = new MyPolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
System.out.println("预启动线程(备战)");
executor.prestartAllCoreThreads(); // 预启动所有核心线程,处于备战
System.out.println("预启动线程数(备战):" + executor.getPoolSize());
for (int i = 1; i <= 10; i++) {
System.out.println(System.currentTimeMillis() + " " + "开始 下发任务:" + i + " 当前线程总数:" + executor.getPoolSize());
MyTask task = new MyTask(String.valueOf(i));
executor.execute(task);
System.out.println(System.currentTimeMillis() + " " + "完成 下发任务:" + i + " 当前线程总数:" + executor.getPoolSize() + " 队列中的线程数量:" + workQueue.size());
Thread.sleep(1); //停1毫秒,日志记录,时间后方便分析
if (i == 9) {
//TODO Thread.sleep(3000); //任务9下发后【会被拒绝】,停3秒,等队列或线程释放后,再下发任务10,这时候任务10不会被拒绝
}
}
System.in.read(); //阻塞主线程
} static class MyTreadFactory implements ThreadFactory { private final AtomicInteger mThreadNum = new AtomicInteger(1); @Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Thread-" + mThreadNum.getAndIncrement());
System.out.println(System.currentTimeMillis() + " " + t.getName() + " has been created");
return t;
}
} public static class MyPolicy implements RejectedExecutionHandler { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 可做日志记录等
System.err.println(System.currentTimeMillis() + " " + r.toString() + " rejected from " + e.toString());
}
} static class MyTask implements Runnable {
private String name; public MyTask(String name) {
this.name = name;
} @Override
public void run() {
try {
Thread mainT = Thread.currentThread();
String taskName = this.name;
SubThread st = new SubThread(taskName, mainT);
Thread thread = new Thread(st);
thread.start();
try {
long millis = 1000;
if (Integer.valueOf(taskName) % 2 == 0) {
millis = Integer.valueOf(taskName) * 2 * millis; //让任务执行慢点
}
System.out.println(System.currentTimeMillis() + " " + this.toString() + " 开始运行! 运行线程 " + Thread.currentThread().getName() + " 需要(秒):" + millis);
Thread.sleep(millis); //让任务执行慢点--这边还是有点问题,如果这个 sleep 过长的话,还是需要等它执行完,并不能解决线程超时杀掉它的目的
System.out.println(System.currentTimeMillis() + " " + this.toString() + " 运行结束! 运行线程 " + Thread.currentThread().getName());
} catch (InterruptedException e) {
System.out.println(System.currentTimeMillis() + " " + this.toString() + " 被打断 运行线程 " + Thread.currentThread().getName());
} finally {
st.setDone(); //通知监控线程,主线程运行结束
//TODO thread.interrupt(); //父线程也可以中止子线程的任务执行
} } catch (Exception e) {
e.printStackTrace();
}
} @Override
public String toString() {
return "MyTask [name=" + this.name + "]";
} static class SubThread implements Runnable {
private String name;
private Thread mainT; //如果完成了就不用杀了。
private boolean isDone; public void setDone() {
isDone = true;
} public SubThread(String name, Thread mainT) {
this.name = name;
this.mainT = mainT;
} @Override
public void run() {
try {
System.out.println(System.currentTimeMillis() + " 子线程 " + Thread.currentThread().getName() + "【正在】监控主进程 " + mainT.getName() + " 任务" + name);
Thread.sleep(5000);
//时间到了,主线程还没有完成就干掉。
if (!isDone) {
mainT.interrupt();
System.out.println(System.currentTimeMillis() + " 子线程 " + Thread.currentThread().getName() + "【杀掉】主进程(超时了) " + mainT.getName() + " 任务" + name);
}
} catch (InterruptedException e) {
System.out.println(System.currentTimeMillis() + " 子线程 " + Thread.currentThread().getName() + "【被打断】" + mainT.getName() + " 任务" + name);
} finally {
System.out.println(System.currentTimeMillis() + " 子线程 " + Thread.currentThread().getName() + "【完成】监控主进程 " + mainT.getName() + " 任务" + name);
}
} @Override
public String toString() {
return "MyTask [name=" + this.name + "]";
}
}
} }
日志排序后:
1655083181083 Thread-1 has been created
1655083181083 Thread-2 has been created
1655083181083 开始 下发任务:1 当前线程总数:2
1655083181084 完成 下发任务:1 当前线程总数:2 队列中的线程数量:1
1655083181085 MyTask [name=1] 开始运行! 运行线程 Thread-2 需要(秒):1000
1655083181085 子线程 Thread-0【正在】监控主进程 Thread-2 任务1
1655083181086 MyTask [name=2] 开始运行! 运行线程 Thread-1 需要(秒):4000
1655083181086 开始 下发任务:2 当前线程总数:2
1655083181086 完成 下发任务:2 当前线程总数:2 队列中的线程数量:1
1655083181086 子线程 Thread-1【正在】监控主进程 Thread-1 任务2
1655083181088 开始 下发任务:3 当前线程总数:2
1655083181088 完成 下发任务:3 当前线程总数:2 队列中的线程数量:1
1655083181089 开始 下发任务:4 当前线程总数:2
1655083181089 完成 下发任务:4 当前线程总数:2 队列中的线程数量:2
1655083181091 开始 下发任务:5 当前线程总数:2
1655083181091 完成 下发任务:5 当前线程总数:2 队列中的线程数量:3
1655083181093 MyTask [name=6] 开始运行! 运行线程 Thread-3 需要(秒):12000
1655083181093 Thread-3 has been created
1655083181093 开始 下发任务:6 当前线程总数:2
1655083181093 完成 下发任务:6 当前线程总数:3 队列中的线程数量:3
1655083181093 子线程 Thread-2【正在】监控主进程 Thread-3 任务6
1655083181095 MyTask [name=7] 开始运行! 运行线程 Thread-4 需要(秒):1000
1655083181095 Thread-4 has been created
1655083181095 开始 下发任务:7 当前线程总数:3
1655083181095 完成 下发任务:7 当前线程总数:4 队列中的线程数量:3
1655083181095 子线程 Thread-3【正在】监控主进程 Thread-4 任务7
1655083181097 MyTask [name=8] 开始运行! 运行线程 Thread-5 需要(秒):16000
1655083181097 Thread-5 has been created
1655083181097 开始 下发任务:8 当前线程总数:4
1655083181097 完成 下发任务:8 当前线程总数:5 队列中的线程数量:3
1655083181097 子线程 Thread-4【正在】监控主进程 Thread-5 任务8
1655083181099 MyTask [name=9] rejected from java.util.concurrent.ThreadPoolExecutor@4b1210ee[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]
1655083181099 开始 下发任务:9 当前线程总数:5
1655083181099 完成 下发任务:9 当前线程总数:5 队列中的线程数量:3
1655083181101 MyTask [name=10] rejected from java.util.concurrent.ThreadPoolExecutor@4b1210ee[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 0]
1655083181101 开始 下发任务:10 当前线程总数:5
1655083181101 完成 下发任务:10 当前线程总数:5 队列中的线程数量:3
1655083182085 MyTask [name=1] 运行结束! 运行线程 Thread-2
1655083182085 MyTask [name=3] 开始运行! 运行线程 Thread-2 需要(秒):1000
1655083182085 子线程 Thread-5【正在】监控主进程 Thread-2 任务3
1655083182095 MyTask [name=4] 开始运行! 运行线程 Thread-4 需要(秒):8000
1655083182095 MyTask [name=7] 运行结束! 运行线程 Thread-4
1655083182095 子线程 Thread-6【正在】监控主进程 Thread-4 任务4
1655083183090 MyTask [name=3] 运行结束! 运行线程 Thread-2
1655083183090 MyTask [name=5] 开始运行! 运行线程 Thread-2 需要(秒):1000
1655083183090 子线程 Thread-7【正在】监控主进程 Thread-2 任务5
1655083184100 MyTask [name=5] 运行结束! 运行线程 Thread-2
1655083185087 MyTask [name=2] 运行结束! 运行线程 Thread-1
1655083186085 子线程 Thread-0【完成】监控主进程 Thread-2 任务1
1655083186086 子线程 Thread-1【完成】监控主进程 Thread-1 任务2
1655083186094 MyTask [name=6] 被打断 运行线程 Thread-3
1655083186094 子线程 Thread-2【杀掉】主进程(超时了) Thread-3 任务6
1655083186094 子线程 Thread-2【完成】监控主进程 Thread-3 任务6
1655083186096 子线程 Thread-3【完成】监控主进程 Thread-4 任务7
1655083186098 MyTask [name=8] 被打断 运行线程 Thread-5
1655083186098 子线程 Thread-4【杀掉】主进程(超时了) Thread-5 任务8
1655083186098 子线程 Thread-4【完成】监控主进程 Thread-5 任务8
1655083187087 子线程 Thread-5【完成】监控主进程 Thread-2 任务3
1655083187103 MyTask [name=4] 被打断 运行线程 Thread-4
1655083187103 子线程 Thread-6【杀掉】主进程(超时了) Thread-4 任务4
1655083187103 子线程 Thread-6【完成】监控主进程 Thread-4 任务4
1655083188098 子线程 Thread-7【完成】监控主进程 Thread-2 任务5
预启动线程(备战)
预启动线程数(备战):2
ThreadPoolExecutor 线程执行超时,释放线程的更多相关文章
- Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行
Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行 Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执 ...
- Java之线程,常用方法,线程同步,死锁
1, 线程的概念 进程与线程 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据 ...
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...
- Java多线程(十)——线程优先级和守护线程
一.线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5.“高优先级线程”会优先于“低优先级线程”执行. java 中有两种线程:用户线程和守护线程.可以通过isDaemon( ...
- Java - 线程优先级和守护线程
Java多线程系列--“基础篇”10之 线程优先级和守护线程 概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注 ...
- java 多线程之 线程优先级和守护线程
线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5."高优先级线程"会优先于"低优先级线程"执行. java 中有两种线程:用户线程和 ...
- java 多线程系列基础篇(十)之线程优先级和守护线程
1. 线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5.“高优先级线程”会优先于“低优先级线程”执行. java 中有两种线程:用户线程和守护线程.可以通过isDaemon ...
- java多线程与线程并发三:线程同步通信
本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程. 有些时候,线程间需要传递消息,比如下面这道面试题: 子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到 ...
- python全栈开发,Day41(线程概念,线程的特点,进程和线程的关系,线程和python理论知识,线程的创建)
昨日内容回顾 队列 队列:先进先出.数据进程安全 队列实现方式:管道+锁 生产者消费者模型:解决数据供需不平衡 管道 双向通信,数据进程不安全 EOFError: 管道是由操作系统进行引用计数的 必须 ...
- Java 多线程基础(十一)线程优先级和守护线程
Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...
随机推荐
- jpa用findAll((Specification<GoodsSpu>) (root, criteriaQuery, criteriaBuilder) -> {})排序
//需要用到的包import org.springframework.data.domain.Page;import org.springframework.data.domain.PageReque ...
- 解决报错Invalid bound statement (not found)
解决报错Invalid bound statement (not found) 问题描述: 在玩mybatis-plus的时候,在测试类写了一个测试批量插入的方法,结果就报错: 它的意思是 无效的跳转 ...
- Java开发者的Python快速进修指南:异常捕获
在之前的学习中,我们已经讲解了函数和控制流等基本概念.然而,在接触实际业务时,你会发现异常捕获也是必不可少的一部分,因为在Java编程中,异常处理是不可或缺的.Python的异常捕获与Java的异常捕 ...
- 在路上---学习篇(一)Python 数据结构和算法 (6)基于GA(遗传)算法的小案例
独白 最近了解到一种算法叫遗传算法,对其比较感兴趣,研究了一下,是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法.遗传算法是从代表问题可 ...
- 【结对作业】第一周 | 学习体会day03
昨天解决线路查询时遇到的type接受为空导致出现空指针异常抛出,后来发现是因为传递的数据类型出现了问题,更改数据类型之后问题就得到了解决今天在实现站点查询线路时遇到了乱码问题,在这之前我们单独编写代码 ...
- 【译】使用 GitHub Copilot 编写 Git 提交
在花费数小时修复 bug 或更新特性之后,我们开发人员最不愿意做的事情往往是仔细说明 Git 提交的内容.最新的 Visual Studio 预览版可以帮到您.使用新的生成 Git 提交消息特性来帮助 ...
- localhost工具:本地代码的远程之路
在日常的开发过程中,本地代码远程调试一直是最理想的开发状态.本文通过介绍京东集团内开发的一个轻量简单的小工具"localhost",从多角度的方案思考,到原理介绍,到最终的方案落地 ...
- 使用nacos配置,启动服务时一直报 Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. APPLICATION FAILED TO START
报错日志如下: Error starting ApplicationContext. To display the conditions report re-run your application ...
- 牛客小白月赛2 D题虚虚实实
题目链接:https://www.nowcoder.com/acm/contest/86/D 解题思路:这题目就是判断是否存在欧拉路径.由无向图存在欧拉路径的充分必要条件可知先判断是否联通,再判断是否 ...
- Celery将任务分发到不同的队列,交给不同的Worker处理
https://docs.celeryq.dev/en/stable/userguide/routing.html#routing-tasks https://blog.csdn.net/wangle ...