代码之家  ›  专栏  ›  技术社区  ›  Uhlen

“单一后进先出执行人/转岗工人”

  •  3
  • Uhlen  · 技术社区  · 15 年前

    考虑一个带有JList或JTable的Swing应用程序,当选择更改时,SwingWorker将启动并从数据库加载相关数据并更新UI。这工作得很好,用户界面也很灵敏。

    但是,如果用户正在快速更改所选行(按住向上/向下键),我希望确保最后一个所选行是最后加载的行,而且我不想徒劳地查询数据库。所以我想要的是一个单线程执行器,其后进先出队列的大小为1。因此,将任务提交给它将删除以前提交的任何任务,并使它一次最多执行一个任务,并且最多有一个任务等待执行。

    我在java.util.concurrent中找不到类似的东西,所以我编写了自己的执行器。我这样做是对的还是我在并发包中遗漏了什么?这个解决方案是可以接受的还是有更好的方法来实现我想要的?

    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);
        }
    }
    

    下面是一个示例,说明如何使用它:

    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 回复  |  直到 15 年前
        1
  •  1
  •   Daniel Ryan    15 年前

    LinkedBlockingDeque似乎仍然使用带有ThreadPoolExecutor的队列。

    因此,我使用了一个包装器并将其与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);
        }
    }
    
        2
  •  0
  •   akf    15 年前

    我相信封锁是你想要的。它支持堆栈。

    我的密码里有什么:

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

    这是我实现的解决方案,对我试图解决的问题非常有效:)

    /**
     * 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);
        }
    }