“单个 LIFO 执行器” / 摇摆工人
考虑一个带有 JList 或 JTable 的 Swing 应用程序,当选择更改时,SwingWorker 会启动并从数据库加载相关数据并更新 UI。这工作正常并且用户界面响应灵敏。
但是,如果用户快速更改所选行(按住向上/向下键),我想确保最后选定的行是最后加载的行,而且我也不想徒劳地查询数据库。所以我想要的是一个单线程执行器,其后进先出队列的大小=1。因此,向其提交任务会删除所有先前提交的任务,并使其一次最多执行 1 个任务,并且最多有 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());
}
}
});
Consider a Swing application with a JList or JTable, when the selection changes a SwingWorker is started and loads related data from database and updates UI. This works fine and the UI is responsive.
But if the user is quickly changing the selected row (holding key-up/down) I want to be sure that the last selected row is the one that is loaded last, and also I don't wanna query the DB in vain. So what I want is an single threaded Executor with a LIFO queue of size=1. So submitting a task to it removes any previous submitted tasks and making it execute at most 1 task at a time and having at most 1 task waiting for execution.
I couldn't find anything like this in java.util.concurrent so I wrote my own Executor. Was I right in doing that or am I missing something from the concurrent package? Is the solution acceptable or is there better ways of achieving 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's an example showing how it could 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());
}
}
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
LinkedBlockingDeque 似乎仍然使用带有 ThreadPoolExecutor 的队列。
因此,我使用了一个包装器并将其与 ThreadPoolExecutor 一起使用:
LinkedBlockingDeque seems to still use Queues with ThreadPoolExecutor.
So instead I used a wrapper and used it with the ThreadPoolExecutor:
BlockingDeque 我相信这就是你想要的。它支持堆栈。
我的代码中有什么:
BlockingDeque I believe is what you want. It supports stacks.
What I have in my code:
这是我实施的解决方案,对于我试图解决的问题非常有效:)
This was the solution I implemented, works great for the problem I tried to solve :)