我有以下课程:
WorkerTask.java
public interface WorkerTask extends Task {
// Constants
public static final short WORKERTASK_SPIDER = 1;
public static final short WORKERTASK_PARSER = 2;
public static final short WORKERTASK_PRODUCT = 3;
public int getType();
}
WorkerPool.java
class workerPool {
private ThreadPoolExecutor executorPool_;
//----------------------------------------------------
public WorkerPool(int poolSize)
{
executorPool_ = new ThreadPoolExecutor(
poolSize,5,10,TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10000000,false),
Executors.defaultThreadFactory()
);
//----------------------------------------------------
public void assign(WorkerTask workerTask) {
executorPool_.execute(new WorkerThread(workerTask));
}
//----------------------------------------------------
public void removeTasks(int siteID) {
executorPool_.getQueue().removeIf(...);
}
}
我想调用方法removeTasks来删除一定数量的挂起任务,但我不知道如何使用removeIf方法。它说:删除此集合中满足给定谓词的所有元素,但我不知道如何创建参数Predicate。有什么想法吗?
答案 0 :(得分:2)
如果您有Queue<WorkerTask>
,则可以执行以下操作:
queue.removeIf(task -> task.getSiteID() == siteID)
有几个问题。一个问题是,您从getQueue()
获得的队列是BlockingQueue<Runnable>
而不是Queue<WorkerTask>
。如果您要向池中提交Runnable
个实例,则队列可能包含对您实际任务的引用;如果是这样,你可以将它们转发给WorkerTask
。但是,这不能保证。此外,ThreadPoolExecutor的课程文档(在“队列维护”下):
方法
getQueue()
允许访问工作队列以进行监视和调试。强烈建议不要将此方法用于任何其他目的。当大量排队的任务被取消时,两个提供的方法remove(Runnable)
和purge()
可用于协助存储回收。
查看remove(Runnable)
方法,其文档说
在放入内部队列之前,可能无法删除已转换为其他表单的任务。
这表明您应该挂在已提交的Runnable
个实例上,以便稍后调用remove()
。或者,请致电submit(Runnable)
以获取Future
并保存这些实例以取消它们。
但是还有第二个问题可能导致这种方法不足。假设您已找到一种方法从队列中删除或取消匹配的任务。另一个线程可能已决定提交匹配的新任务,但尚未提交。这里有竞争条件。您可以取消已排队的任务,但在完成后,您无法保证尚未提交新的匹配任务。
这是另一种方法。据推测,当你取消(或者不管)某个站点ID时,有一些逻辑可以停止提交与该ID相匹配的新任务。问题是如何处理“正在进行中”的匹配任务,即队列中或即将入队的匹配任务。
不是尝试取消匹配的任务,而是更改任务,以便在取消其站点ID时,任务变为无操作。您可以在ConcurrentHashMap
中记录网站ID的取消。任何任务都会在开始工作之前检查此地图,如果网站ID存在,则只返回。向站点添加站点ID将立即生效,确保不会开始该站点ID上的新任务。 (已经开始的任务将运行完成。)任何正在进行的任务最终将从队列中排出,而不会导致任何实际工作发生。
答案 1 :(得分:0)
谓词是一个接收输入并返回布尔值的函数。
如果您使用的是Java 8,则可以使用lambda表达式:
(elem) -> return elem.id == siteID