如何在ArrayBlockingQueue中使用Predicate方法“removeIf”

时间:2016-01-11 11:23:52

标签: java collections predicate threadpoolexecutor remove-if

我有以下课程:

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。有什么想法吗?

2 个答案:

答案 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