Sun Java(1.6)ScheduledThreadPoolExecutor
是ThreadPoolExecutor
的扩展,在内部使用DelayQueue
的实现,它是无界队列。我需要的是ScheduledThreadpoolExecutor
带有有界队列,即它对队列中累积的任务有限制,这样当队列中的任务超过限制时,它就会开始拒绝进一步提交的任务并防止JVM内存不足。
令人惊讶的是,google或stackoverflow没有指出任何讨论此问题的结果。有没有这样的东西可用我错过了?如果没有,我如何实现ScheduledThreadpoolExecutor以最佳方式提供我期望的功能?
答案 0 :(得分:5)
正如其他人已经指出的那样,没有一种方法可以做到这一点。只要确保你尝试使用“组合”而不是“继承”。通过根据必要方法的要求进行检查,创建一个实现必要接口并委托给基础ScheduledThreadPoolExecutor
的新类。
您还可以使用this thread中指定的技术进行简单修改。您可以使用Semaphore#acquire
而不是使用Semaphore#tryAcquire
,并根据布尔结果决定是否需要调用拒绝处理程序。考虑到这一点,我个人觉得图书馆作者的一个疏忽是直接将特定的执行者子类化,而不是依靠组合来创建一个正常执行者的“可调度”包装器。
答案 1 :(得分:2)
如何以不同方式处理它,即根据队列大小延迟任务提交。执行程序服务通过getQueue()公开队列。您可以调用它上面的size(),并根据您为队列大小规划的限制,您可以开始拒绝任务或开始延迟任务执行(增加计划时间,保持队列大小作为因素之一) )。
所有人都说,这也不是最好的解决方案;只是fyi,java提供延迟队列来支持工作窃取。
答案 2 :(得分:1)
最简单的解决方法是使用预定执行程序来仅安排任务,而不是实际执行它们。如果执行程序队列高于阈值,则调度程序必须显式检查执行程序队列大小并丢弃任务。
另一种选择是在计划任务中检查ScheduledThreadPoolExecutor队列大小。如果队列高于阈值,则立即返回。在这种情况下,任务将立即执行并从队列中删除。所以溢出不会发生。
答案 3 :(得分:1)
ScheduledThreadPoolExecutor不使用队列作为字段,而是调用getQueue。但它调用super.getQueue,它是ThreadPoolExecutor的队列。您可以使用反射覆盖它,如下所示:
public class BoundedScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
public BoundedScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler, int queueCapacity) {
super(corePoolSize, handler);
setMaximumPoolSize(corePoolSize);
setKeepAliveTime(0, TimeUnit.MILLISECONDS);
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueCapacity) {
@Override
public boolean add(Runnable r) {
boolean added = offer(r);
if (added) {
return added;
} else {
getRejectedExecutionHandler().rejectedExecution(r, CrashingThreadPoolExecutor.this);
return false;
}
}
};
try {
Field workQueueField = ThreadPoolExecutor.class.getDeclaredField("workQueue");
workQueueField.setAccessible(true);
workQueueField.set(this, queue);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
答案 4 :(得分:0)
如果你真的,真的不想重新实现ScheduledThreadPoolExecutor
那么你可以扩展它并覆盖所有schedule*
方法并实现你自己的任务边界。但这会很糟糕:
private final Object scheduleMonitor = new Object();
@Override
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit)
{
if (command == null || unit == null)
throw new NullPointerException();
synchronized (scheduleMonitor)
{
while (getQueue().size() >= MAX_QUEUE_SIZE)
{
scheduleMonitor.wait();
}
super.schedule(command, delay, unit);
}
}
@Override
Runnable getTask()
{
final Runnable r = getTask();
synchronized (scheduleMonitor)
{
scheduleMonitor.notify();
}
return r;
}
并重复:
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit)
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit)
注意,这不会阻止重复任务使队列超过限制,它只会阻止新计划的任务。
另一个警告是,我在super.schedule
暂停锁定时调用scheduleMonitor
时没有检查任何死锁问题...