2010-11-13 101 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); 
    } 
}