考虑使用JList或JTable的Swing应用程序,当选择更改时,SwingWorker启动并从数据库和更新UI加载相关数据。这很好用,用户界面也很敏感。
但是如果用户正在快速更改所选行(按住向上/向下键),我想确保最后选择的行是最后加载的行,而且我也不想查询数据库中的徒劳的。所以我想要的是具有大小= 1的LIFO队列的单线程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 :(得分: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);
}
}
答案 1 :(得分:0)
BlockingDeque我相信你想要的。它支持堆栈。
我的代码中包含的内容:
private transient final ExecutorService threadPool=
new ThreadPoolExecutor(3, 10,10,
TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<Runnable>());
答案 2 :(得分: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);
}
}