我正在寻找一个具有未知池大小的ScheduledThreadPoolExecutor。池大小在运行时确定,可能在1-5之间,对于此示例,我使用大小2.我们使用自定义任务,每隔一段时间执行一次方法,但该方法最终会抛出异常(我用一个简单的numTimes变量和if语句模拟了。如果抛出异常,我只想取消执行THAT特定线程!如果所有线程都被取消,我想关闭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上调用shutdown,但它没有完成线程执行。注释掉stpe.shutdown创建了两个目录,否则它们不是。
我无法找到一种优雅的方法来取消ScheduledFuture,然后取消所有ScheduledFuture取消时的ScheduledThreadPoolExecutor。
我无法按照下面的答案中所述让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);
}
}
}
答案 0 :(得分:3)
您需要在池上发出关闭。 JVM将继续运行,直到只有守护程序线程处于活动状态。默认情况下, ThreadPoolExecutor 将创建非守护程序线程。
只需调用stpe.shutdown();
编辑:基于OP更新
对于ScheduledThreadPoolExecugtor而言, shutdown
与普通的ThreadPoolExecutor不同。在这种情况下,shutdown
会阻止重新安排任何计划任务。为了使其正常工作,您必须等待期货完成。您可以get()
ScheduledFuture
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完成并最终关闭。