简体   繁体   中英

rxJava Ordered (by key) task execution

I have a bunch of objects representing some data. These objects can be written to their corresponding files. User may request some changes to be made quicker than previous changes written to the file.

Say, I make changes to File A, File B and File C and submit them for execution. Then, while they are being written, I make changes to File A and post it. For instance, there are 3 threads operating. Once first changes to A, B and C executed (written to files), 1st and 2nd changes to A will be executed almost simultaneously. However, I want the 2nd change to be applied after the 1st one is done.

How can I do that in rxJava?

Another point. In a different place I want to run action with the latest changes. One option is to wait until all tasks finished.

Is there appropriate RxJava primitive/approach that would hopefully cover these 2 use cases?

I am new to RxJava, but I hope this makes sense. Subjects come to my mind as relevant, but there gonna be hundreds of files.

I already have the implementation using custom Executor .

public class OrderingExecutor
implements Executor
{
    @Delegate
    private final Executor delegate;
    private final Map<Object, Queue<Runnable>> keyedTasks = new HashMap<>();

    public OrderingExecutor(
        Executor delegate)
    {
        this.delegate = delegate;
    }

    public void execute(
        Runnable task,
        Object key)
    {
        Objects.requireNonNull(key);

        boolean first;
        Runnable wrappedTask;
        synchronized (keyedTasks)
        {
            Queue<Runnable> dependencyQueue = keyedTasks.get(key);
            first = (dependencyQueue == null);
            if (dependencyQueue == null)
            {
                dependencyQueue = new LinkedList<>();
                keyedTasks.put(key, dependencyQueue);
            }

            wrappedTask = wrap(task, dependencyQueue, key);
            if (!first)
            {
                dependencyQueue.add(wrappedTask);
            }
        }

        // execute method can block, call it outside synchronize block
        if (first)
        {
            delegate.execute(wrappedTask);
        }

    }

    private Runnable wrap(
        Runnable task,
        Queue<Runnable> dependencyQueue,
        Object key)
    {
        return new OrderedTask(task, dependencyQueue, key);
    }

    class OrderedTask
    implements Runnable
    {

        private final Queue<Runnable> dependencyQueue;
        private final Runnable task;
        private final Object key;

        public OrderedTask(
            Runnable task,
            Queue<Runnable> dependencyQueue,
            Object key)
        {
            this.task = task;
            this.dependencyQueue = dependencyQueue;
            this.key = key;
        }

        @Override
        public void run()
        {
            try
            {
                task.run();
            }
            finally
            {
                Runnable nextTask = null;
                synchronized (keyedTasks)
                {
                    if (dependencyQueue.isEmpty())
                    {
                        keyedTasks.remove(key);
                    }
                    else
                    {
                        nextTask = dependencyQueue.poll();
                    }
                }
                if (nextTask != null)
                {
                    delegate.execute(nextTask);
                }
            }
        }
    }
}

Maybe some sensible way to plug it into rxJava?

It's not fully clear what you try to achieve here, but you can layer a priority queue on top of RxJava.

class OrderedTask implements Comparable<OrderedTask> { ... }

PriorityBlockingQueue<OrderedTask> queue = new PriorityBlockingQueue<>();

PublishSubject<Integer> trigger = PublishSubject.create();

trigger.flatMap(v -> {
   OrderedTask t = queue.poll();
   return someAPI.workWith(t);
}, 1)
.subscribe(result -> { }, error -> { });

queue.offer(new SomeOrderedTask(1));
trigger.onNext(1);

queue.offer(new SomeOrderedTask(2));
trigger.onNext(2);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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