我正在创建一个池大小未知的 ScheduledThreadPoolExecutor。池大小在运行时确定,可能在 1-5 之间,在本例中我使用大小 2。我们使用一个自定义任务,它只是每隔一段时间执行一个方法,但该方法最终会抛出一个异常(我用一个简单的 numTimes 变量和 if 语句进行了模拟)。如果抛出异常,我只想取消该特定线程的执行!如果所有线程都被取消,我想关闭ScheduledThreadPoolExecutor。一旦 numTimes == 5,我就模拟异常来取消线程),并且我可以通过多种方式设法取消线程,但它们就是感觉不对。
作为旁注,我将 ScheduledFuture 放置在各处只是为了尝试取消它。
public class Test
{
static ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(2);
public static void main(String[] args)
{ stpe.scheduleWithFixedDelay(new UpdateTask(1), 0, 1000, TimeUnit.MILLISECONDS);
stpe.scheduleWithFixedDelay(new UpdateTask(2), 0, 5000, TimeUnit.MILLISECONDS);
// stpe.shutdown();
}
public static class UpdateTask implements Runnable
{
int id;
int numTimes = 0;
ScheduledFuture<?> t;
public UpdateTask(int id)
{ this.id = id;
}
public void run()
{ System.out.println("Hello " + id + " num: " + numTimes);
String fn = "C:\\lib" + id;
if (numTimes++ == 5)
{ File f = new File(fn);
f.mkdir();
t.cancel(false);
}
}
}
}
从 run() 或 main() 调用 t.cancel() 具有相同的效果,线程停止执行,但程序不会停止运行。当然,这是因为 ThreadPoolExecutor 仍在执行任务,尽管两个线程不再被调度。
我尝试在 stpe 上调用关闭,但它没有完成线程执行。创建两个目录时将 stpe.shutdown 注释掉,否则不会。
我想不出一种优雅的方法来取消 ScheduledFuture,然后在取消所有 ScheduledFuture 时取消 ScheduledThreadPoolExecutor。
final方法##
我无法让 s1.get() 按照下面的答案中的描述工作,所以我只是创建了自己的类来处理它。
public class Test
{
static ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(2);
static CancelUpdateTasks canceller;
public static void main(String[] args)
{ Test t = new Test();
canceller.add(0, stpe.scheduleWithFixedDelay(new UpdateTask(0), 0, 1000, TimeUnit.MILLISECONDS));
canceller.add(1, stpe.scheduleWithFixedDelay(new UpdateTask(1), 0, 5000, TimeUnit.MILLISECONDS));
canceller.waitForSchedules();
stpe.shutdown();
}
public Test()
{ canceller = new CancelUpdateTasks();
}
public static class UpdateTask implements Runnable
{
int id;
int numTimes = 0;
public UpdateTask(int id)
{ this.id = id;
}
public void run()
{ System.out.println("Hello " + id + " num: " + numTimes);
if (numTimes++ == 5)
{ canceller.cancel(id);
}
}
}
public class CancelUpdateTasks
{ List<ScheduledFuture<?>> scheduler;
boolean isScheduled;
public CancelUpdateTasks()
{ scheduler = new ArrayList<ScheduledFuture<?>>();
isScheduled = false;
}
public void waitForSchedules()
{ int schedId = 0;
while(isScheduled)
{ ScheduledFuture<?> schedule = scheduler.get(schedId);
if (schedule.isCancelled())
{ if (schedId == scheduler.size() - 1)
return;
schedId++;
}
else
{ try
{ Thread.sleep(1000);
}
catch (InterruptedException e)
{ e.printStackTrace();
}
}
}
}
public void add(int id, ScheduledFuture<?> schedule)
{ scheduler.add(id, schedule);
if (!isScheduled)
isScheduled = true;
}
public void cancel(int id)
{ scheduler.get(id).cancel(false);
}
public void cancelNow(int id)
{ scheduler.get(id).cancel(true);
}
}
}
最佳答案
您需要关闭池。 JVM 将继续运行,直到只有守护线程处于 Activity 状态。默认情况下,ThreadPoolExecutor 将创建非守护线程。
只需调用stpe.shutdown();
编辑:基于OP更新
shutdown
诚然,ScheduledThreadPoolExecutor 的关闭与普通 ThreadPoolExecutor 不同。在这种情况下,shutdown
会阻止任何计划任务重新计划。为了使其正常工作,您必须等待 future 完成。您可以通过 ScheduledFuture
get()
来完成此操作
ScheduledFuture sf1 = stpe.scheduleWithFixedDelay(new UpdateTask(1), 0, 1000, TimeUnit.MILLISECONDS);
ScheduledFuture sf2 = stpe.scheduleWithFixedDelay(new UpdateTask(2), 0, 5000, TimeUnit.MILLISECONDS);
sf1.get();
sf2.get();
stpe.shutdown();
在这种情况下,两个任务都是异步运行的,主线程将首先等待 sf1 完成,然后等待 sf2 完成,最后关闭。
关于java - 即使 ScheduledFuture 被取消,ThreadPoolExecutor 也会运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20977932/