当前位置:网站首页>关于线程池中终止任务
关于线程池中终止任务
2022-07-17 05:09:00 【秦汉春秋】
使用线程池本身删除或终止任务,有一个必须的前提:
任务必须存在于队列之中。
为什么这么说?
是因为我们所谓的“删除任务”是指ThreadPoolExecutor的remove方法:
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
可以看到,是需要从workQueue中移除的;
也就是说,如果已经运行的任务,理论上是无法使用线程池进行删除操作的。
比如:
private static void testNormalRemove() {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(1, 3, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3));
Thread task1 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("normal1," + Thread.currentThread().getId());
}
}
});
Thread task2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
System.out.println("normal2," + Thread.currentThread().getId());
}
}
});
tpe.execute(task1);
tpe.execute(task2);
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tpe.getQueue().size());
System.out.println("remove task2," + tpe.remove(task2));
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这里有task1、task2两个任务,创建的线程池核心线程为1,那么task1被添加后会被马上运行,而task2会添加入队列等待运行,原理可参考线程池原理浅析,那么task2是可以被remove成功的,而task1是不能被remove的,因为根本不在队列之中了。
当然,存在一些特殊的线程池,每个任务其实都加入了队列,比如ScheduledThreadPoolExecutor添加任务时,其实每个任务都被添加进了队列:
public void execute(Runnable command) {
schedule(command, 0, NANOSECONDS);
}
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
if (isShutdown())
reject(task);
else {
super.getQueue().add(task);
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
这样添加进来的任务是可以进行删除操作的;
当然需要注意的是添加的任务被封装成了RunnableScheduledFuture,所以删除的时候也要记得转换为RunnableScheduledFuture再进行删除,如果是使用schedule或其他scheduleXX方法,会直接返回RunnableScheduledFuture,可以就返回值来进行删除操作。
而其他线程池则没这么“好运”了,遵循一般规则,仅在超出corePoolSize时才会加入队列;
线程池内部倒是有停止线程的方法,但线程池内部的调度方法大多是private,是无法调用的,比如这个:
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
//略
}
已经运行的线程或者任务都被封装为Worker,但关于Worker的方法并不对外开放,这也是大多线程池无法精细控制线程的原因——当然,线程本身就很说去精细控制。
总体来说,线程一旦启动,就很难通过常规手段去停止,往往需要抛出异常或添加return或者强行interrupt来停止;
如果需要对线程进行一定的掌握,那么使用类似于ScheduledThreadPoolExecutor的线程池在某些场景也不失为一个优良的选择。
边栏推荐
猜你喜欢

Talk about 12 business scenarios of concurrent programming

ArcGIS point cloud (XYZ) data to DEM

Swagger configuration and use

MySQL事务

MySQL lock

聊聊写代码的20个反面教材

Ambari2.7.5 integration es6.4.2

Online software testing training institutions lemon class and itest AI platform achieves strategic cooperation

C语言的宏定义

Use Flink SQL to transfer market data 1: transfer VWAP
随机推荐
5. Spark core programming (1)
Common methods of goframe error handling & use of error codes
MySQL--存储和游标
Ambari2.7.5 integration es6.4.2
A comprehensive performance optimization, from 5 seconds to 1 second
Minor problems of GCC compiling C language in ubantu
zTree自定义Title属性
特殊指针的一些应用
Questions d'entrevue courantes du système d'exploitation
Common (Consortium)
PCM静默检测
1 sparksql overview
replace限制文本框只能输入数字,数字和字母等的正则表达式
UML (use case diagram, class diagram, object diagram, package diagram)
MySQL安装配置教程(超级详细)
【Bug解决】org.apache.ibatis.type.TypeException: The alias ‘xxxx‘ is already mapped to the value ‘xxx‘
MySQL学习笔记(5)——JOIN联表查询,自连接查询,分页和排序,子查询与嵌套查询
Operation of C language files
Use of log4j
ETL工具——kettle实现简单的数据迁移