Question

I have an application without a save button; saving happens automatically in the background. As the user works with the app, tasks are created and put into a queue for execution. Some of them are delayed, for example, when you start typing, I wait 200ms before I update the corresponding value in the database.

To make this more simple to use code wise, I'd like to be able to add a task to the queue with a delay and a "key". If there is already a task with the same "key", then my second task should be ignored (because the same operation is already queued).

Does something like that already exist?

Was it helpful?

Solution

I think you should look into TreeMap class. Use the constructor which let you pass a Comparator. This way you can let the Map sort on Delayed (since this class implements Comparable interface). Before adding a "Task" to the map, check if the key already exists using containsKey method.

OTHER TIPS

This is how I understood the question and would take the challenge:

A task wrapper wraps a task or command and adds the additional values, the delay for the task and the identifier. I understood, that two tasks may have the same 'key', so we can't just take the tasks hashvalue.

public TaskWrapper<T> {
   private T task;
   private long delayInMillis;
   private long key;

   public TaskWrapper(T task, long delayInMillis, long key) {
     this.task = task;
     this.delayInMillis = delayInMillis;
     this.key = key;
   }

   // getter, setters, and so on

   public boolean equals(Object o) {
      if (o == null || !(o instanceof TaskWrapper)) return false;
      return key == ((TaskWrapper) o).key;
   }
}

A queue decorator adds the 'set' like behaviour. A queue doesn't have 'contains' method, so I take an additional Set to record the objects that are actually enqued. All methods that change the queue will be implemented to keep the consistency between the internal queue and the set. This quick draft is not thread safe and shows just the add method.

public SetQueue<TaskWrapper> implements Queue<T> {
  private Queue<TaskWrapper> queue;
  private Set<TaskWrapper> set = new HashSet<TaskWrapper>();

  public SetQueue(Queue<TaskWrapper> queue) {
    this.queue = queue;
  }

  // just to demonstrate the idea
  public boolean add(TaskWrapper<?> task) {
     if (set.contains(task) 
        return false;
     boolean result = queue.add(task);
     if (result) 
        set.add(task);
     return result;
  }

(may be full of bugs, I don't have an IDE at hand. It's just a draft)

One of the elegant solution that came into my mind: use a thread pool executer that has a priority blocking queue as working queue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top