2010-11-13 103 views
3

考虑具有JList或JTable的Swing应用程序,当选择更改时,SwingWorker将启动并从数据库加载相关数据并更新UI。这工作正常,用户界面响应。“单个LIFO执行器”/ SwingWorker

但是,如果用户正在快速更改选定的行(保持键入/关闭)我想确保最后选择的行是最后一个加载的行,并且我也不想查询数据库徒然。所以我想要的是一个带有LIFO队列大小为1的单线程Executor。因此,向其提交任务会删除任何先前提交的任务,并一次执行至多1个任务,并且最多只有1个任务正在等待执行。

我在java.util.concurrent中找不到像这样的东西,所以我写了自己的Executor。我是对的吗?还是我错过了并发包中的一些东西?解决方案是可以接受的还是有更好的方法来实现我想要的?

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

回答

0

这是我实现的解决方案,能很好的完成这个问题我试图解决:)

/** 
* 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

BlockingDeque我相信这是你想要的。它支持堆栈。

我有我的代码是什么:

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

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