LIFO Single Artist / SwingWorker

Consider a Swing application with a JList or JTable when the choice modifies the launch of SwingWorker and loads related data from the database and updates the user interface. This works great and the user interface is responsive.

But if the user quickly changes the selected row (holding the up / down key), I want to be sure that the last selected row is the one that was loaded last, and I also do not want to query the database in vain. So what I want is a single-threaded executor with a LIFO queue of size = 1. Thus, sending a task to it deletes all previous tasks set and forces it to perform no more than 1 task at a time and has no more than 1 task waiting to be completed.

I could not find anything like it in java.util.concurrent, so I wrote my own Executor. Was I right about this, or am I missing something from the parallel package? Is the solution acceptable or are there better ways to achieve what I want?

public class SingleLIFOExecutor implements Executor
{
    private final ThreadPoolExecutor executor;
    private Runnable lastCommand;

    public SingleLIFOExecutor()
    {
        executor = new ThreadPoolExecutor(0, 1, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
    }

    @Override
    public void execute(Runnable command)
    {
        executor.remove(lastCommand);
        lastCommand = command;
        executor.execute(command);
    }
}

And here is an example showing how it can be used:

final Executor executor = new SingleLIFOExecutor();
JList jList = createMyList();
jList.addListSelectionListener(new ListSelectionListener()
{
    @Override
    public void valueChanged(ListSelectionEvent e)
    {
        if (!e.getValueIsAdjusting())
        {
            executor.execute(new MyWorker());
        }
    }
});
+3
source share
3 answers

This was the solution that I implemented, works great for the problem I was trying to solve :)

/**
 * A "Single Last-In-First-Out Executor".
 * <p>
 * It maintains a queue of <b>one</b> task and only one task may execute simultaneously,
 * submitting a new task to {@link #execute(Runnable)} will discard any previous submitted not yet started tasks.
 */
public class SingleLIFOExecutor implements Executor
{
    private final ThreadPoolExecutor executor;
    private Runnable lastCommand;

    public SingleLIFOExecutor()
    {
        executor = new ThreadPoolExecutor(0, 1, 0, MILLISECONDS, new ArrayBlockingQueue<Runnable>(1));
    }

    /**
     * @see java.util.concurrent.Executor#execute(java.lang.Runnable)
     */
    @Override
    public void execute(Runnable command)
    {
        executor.remove(lastCommand);
        lastCommand = command;
        executor.execute(command);
    }
}
0
source

LinkedBlockingDeque still uses queues with ThreadPoolExecutor.

So instead, I used a wrapper and used it with ThreadPoolExecutor:

package util;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

/**
 * LIFO BlockingQueue to be used with the ExecutorService.
 * @author Daniel
 * @param <T>
 */
public class LinkedBlockingStack<T> implements BlockingQueue<T>{
    private final LinkedBlockingDeque<T> stack = new LinkedBlockingDeque<T>();

    @Override
    public T remove() {
        return stack.remove();
    }

    @Override
    public T poll() {
        return stack.poll();
    }

    @Override
    public T element() {
        return stack.element();
    }

    @Override
    public T peek() {
        return stack.peek();
    }

    @Override
    public int size() {
        return stack.size();
    }

    @Override
    public boolean isEmpty() {
        return stack.isEmpty();
    }

    @Override
    public Iterator<T> iterator() {
        return stack.iterator();
    }

    @Override
    public Object[] toArray() {
        return stack.toArray();
    }

    @Override
    public <S> S[] toArray(final S[] a) {
        return stack.toArray(a);
    }

    @Override
    public boolean containsAll(final Collection<?> c) {
        return stack.containsAll(c);
    }

    @Override
    public boolean addAll(final Collection<? extends T> c) {
        return stack.addAll(c);
    }

    @Override
    public boolean removeAll(final Collection<?> c) {
        return stack.removeAll(c);
    }

    @Override
    public boolean retainAll(final Collection<?> c) {
        return stack.removeAll(c);
    }

    @Override
    public void clear() {
        stack.clear();
    }

    @Override
    public boolean add(final T e) {
        return stack.offerFirst(e); //Used offerFirst instead of add.
    }

    @Override
    public boolean offer(final T e) {
        return stack.offerFirst(e); //Used offerFirst instead of offer.
    }

    @Override
    public void put(final T e) throws InterruptedException {
        stack.put(e);
    }

    @Override
    public boolean offer(final T e, final long timeout, final TimeUnit unit)
    throws InterruptedException {
        return stack.offerLast(e, timeout, unit);
    }

    @Override
    public T take() throws InterruptedException {
        return stack.take();
    }

    @Override
    public T poll(final long timeout, final TimeUnit unit)
    throws InterruptedException {
        return stack.poll();
    }

    @Override
    public int remainingCapacity() {
        return stack.remainingCapacity();
    }

    @Override
    public boolean remove(final Object o) {
        return stack.remove(o);
    }

    @Override
    public boolean contains(final Object o) {
        return stack.contains(o);
    }

    @Override
    public int drainTo(final Collection<? super T> c) {
        return stack.drainTo(c);
    }

    @Override
    public int drainTo(final Collection<? super T> c, final int maxElements) {
        return stack.drainTo(c, maxElements);
    }
}
+1
source

BlockingDeque , . .

:

private transient final ExecutorService threadPool= 
     new ThreadPoolExecutor(3, 10,10, 
                            TimeUnit.MILLISECONDS, 
                            new LinkedBlockingDeque<Runnable>());
0

Source: https://habr.com/ru/post/1774710/


All Articles