简体   繁体   English

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

[英]How to use the method “removeIf” using a Predicate in a ArrayBlockingQueue

I have the following classes: 我有以下课程:

WorkerTask.java 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 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(...);     
     }
}

I want to call the method removeTasks to remove certain amount of pending tasks but I have no idea of how to use the method removeIf. 我想调用方法removeTasks来删除一定数量的挂起任务,但我不知道如何使用方法removeIf。 It says: Removes all of the elements of this collection that satisfy the given predicate, but I have no idea how to create the parameter Predicate. 它说:删除此集合中满足给定谓词的所有元素,但我不知道如何创建参数Predicate。 Any idea? 任何的想法?

If you had a Queue<WorkerTask> , you could do something like this: 如果你有一个Queue<WorkerTask> ,你可以这样做:

queue.removeIf(task -> task.getSiteID() == siteID)

There are several problems. 有几个问题。 One problem is that the queue you get from getQueue() is BlockingQueue<Runnable> and not Queue<WorkerTask> . 一个问题是你从getQueue()获得的队列是BlockingQueue<Runnable>而不是Queue<WorkerTask> If you're submitting Runnable instances to the pool, the queue might contain references to your actual tasks; 如果要将Runnable实例提交到池中,则队列可能包含对实际任务的引用; if so, you could downcast them to WorkerTask . 如果是这样,你可以将它们WorkerTaskWorkerTask However, this isn't guaranteed. 但是,这不能保证。 Furthermore, the class doc for ThreadPoolExecutor says (under "Queue maintenance"): 此外, ThreadPoolExecutor的类doc说(在“队列维护”下):

Method getQueue() allows access to the work queue for purposes of monitoring and debugging. 方法getQueue()允许访问工作队列以进行监视和调试。 Use of this method for any other purpose is strongly discouraged. 强烈建议不要将此方法用于任何其他目的。 Two supplied methods, remove(Runnable) and purge() are available to assist in storage reclamation when large numbers of queued tasks become cancelled. 当大量排队的任务被取消时,两个提供的方法remove(Runnable)purge()可用于协助存储回收。

Looking at the remove(Runnable) method, its doc says 查看remove(Runnable)方法,其文档说

It may fail to remove tasks that have been converted into other forms before being placed on the internal queue. 在放入内部队列之前,它可能无法删除已转换为其他表单的任务。

This suggests that you should hang onto the Runnable instances that have been submitted in order to call remove() on them later. 这表明您应该挂起已提交的Runnable实例,以便稍后调用remove() Or, call submit(Runnable) to get a Future and save those instances around in order to cancel them. 或者,调用submit(Runnable)获取Future并保存这些实例以取消它们。

But there is also a second problem that probably renders this approach inadequate. 但是还有第二个问题可能导致这种方法不足。 Suppose you've found a way to remove or cancel the matching tasks from the queue. 假设您已找到一种方法从队列中删除或取消匹配的任务。 Another thread might have decided to submit a new task that matches, but hasn't submitted it yet. 另一个线程可能已决定提交匹配的新任务,但尚未提交。 There's a race condition here. 这里有竞争条件。 You might be able to cancel the enqueued tasks, but after you've done so, you can't guarantee that new matching tasks haven't been submitted. 您可以取消已排队的任务,但在完成之后,您无法保证尚未提交新的匹配任务。

Here's an alternative approach. 这是另一种方法。 Presumably, when you cancel (or whatever) a site ID, there's some logic somewhere to stop submitting new tasks that match that side ID. 据推测,当你取消(或者不管)某个站点ID时,有一些逻辑可以停止提交与该ID相匹配的新任务。 The problem is how to deal with matching tasks that are "in-flight," that is, that are in the queue or are about to be enqueued. 问题是如何处理“在飞行中”的匹配任务,即队列中或即将入队的任务。

Instead of trying to cancel the matching tasks, change the task so that if its site ID has been canceled, the task turns into a no-op. 不要尝试取消匹配的任务,而是更改任务,以便在其网站ID被取消后,任务变为无操作。 You could record the cancellation of a site ID in, say, a ConcurrentHashMap . 您可以在ConcurrentHashMap记录网站ID的取消。 Any task would check this map before beginning its work, and if the site ID is present, it'd simply return. 任何任务都会在开始工作之前检查此地图,如果网站ID存在,则只返回。 Adding a site ID to the map would have the immediate effect of ensuring that no new task on that site ID will commence. 向站点添加站点ID将立即生效,确保不会开始该站点ID上的新任务。 (Tasks that have already started will run to completion.) Any in-flight tasks will eventually drain from the queue without causing any actual work to occur. (已经启动的任务将运行完成。)任何正在进行的任务最终将从队列中排出,而不会导致任何实际工作发生。

A predicate is a function that receives an input and returns a boolean value. 谓词是一个接收输入并返回布尔值的函数。

If you are using java 8 you can use lambda expressions: (elem) -> return elem.id == siteID 如果您使用的是java 8,则可以使用lambda表达式: (elem) -> return elem.id == siteID

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM