我有一个用例来自一个GUI问题,我想提交给您的智慧。
用例
我有一个GUI,它根据用户在GUI中设置的一些参数显示计算结果。例如,当用户移动滑块时,会触发多个事件,这些事件都会触发新的计算。当用户将滑块值从A调整到B时,会触发数十个事件。
但是计算时间可以长达几秒钟,而滑块调整可以每隔100 ms触发一次事件。
如何编写一个正确的线程来侦听这些事件,并对它们进行过滤,以便重新绘制结果是生动的?理想情况下,你会喜欢这样的东西
我已经尝试过的
我的一个朋友(A. Cardona)提出了一种低级别的更新线程方法,它可以防止太多事件触发计算。我在这里复制粘贴它(GPL):
他把它放在一个扩展Thread的类中:
public void doUpdate() {
if (isInterrupted())
return;
synchronized (this) {
request++;
notify();
}
}
public void quit() {
interrupt();
synchronized (this) {
notify();
}
}
public void run() {
while (!isInterrupted()) {
try {
final long r;
synchronized (this) {
r = request;
}
// Call refreshable update from this thread
if (r > 0)
refresh(); // Will trigger re-computation
synchronized (this) {
if (r == request) {
request = 0; // reset
wait();
}
// else loop through to update again
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void refresh() {
// Execute computation and paint it
...
}
每次事件由图形用户界面发送,声明参数已被更改,我们称之为updater.doUpdate()
。这导致调用refresh()
方法的次数要少得多。但我无法控制这件事。
换条路?
我想知道是否还有其他方法可以使用jaca.concurrent类。但是,我不能在执行者的框架中对我应该从哪一个开始进行排序。
你们中有谁对类似的用例有一些经验吗?
谢谢
发布于 2013-03-14 15:39:36
如果您正在使用Swing
,则SwingWorker
提供了这方面的功能,您不必自己处理线程池。
为每个请求启动一个SwingWorker
。如果一个新请求传入,而工作人员未完成,您可以对其进行cancel()
,并启动一个新的SwingWorker
。关于另一张海报上说的话,我不认为publish()
和process()
是您要寻找的(尽管它们也非常有用),因为它们的目的是在这样的情况下,工作人员可能会比GUI更快地触发事件。
ThingyWorker worker;
public void actionPerformed(ActionEvent e) {
if( worker != null ) worker.cancel();
worker = new ThingyWorker();
worker.execute();
}
class ThingyWorker extends SwingWorker<YOURCLASS, Object> {
@Override protected YOURCLASS doInBackground() throws Exception {
return doSomeComputation(); // Should be interruptible
}
@Override protected void done() {
worker = null; // Reset the reference to worker
YOURCLASS data;
try {
data = get();
} catch (Exception e) {
// May be InterruptedException or ExecutionException
e.printStackTrace();
return;
}
// Do something with data
}
}
操作和done()
方法都是在同一个线程上执行的,因此它们可以有效地检查对是否存在现有工作人员的引用。
请注意,这实际上是在执行允许GUI取消现有操作的相同操作,除非在触发新请求时自动完成取消操作。
发布于 2013-03-14 15:16:53
我将通过使用队列在GUI和控件之间提供更大程度的断开。
如果在两个进程之间使用BlockingQueue
。每当控件更改时,您都可以将新设置张贴到队列中。
您的图形组件可以随时读取队列,并对到达的事件采取行动或在必要时丢弃它们。
发布于 2013-03-14 15:28:52
我将查看SwingWorker.publish() (http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html)
发布允许SwingWorker对象的后台线程导致对process()方法的调用,但并不是每个发布()调用都会导致进程()调用。如果在process()返回之前进行了多个进程调用,并且可以再次调用,则SwingWorker将用于将多个发布调用连接到一个进程调用中的参数连接起来。
我有一个显示正在处理的文件的进度对话框;这些文件的处理速度比UI能够跟上它们的速度要快,而且我不希望处理速度减慢以显示文件名;我使用这个对话框,只显示发送给process ()的最后文件名;在本例中,我只想向用户指示当前处理的位置,他们无论如何都不会读取所有文件名。我的UI在这方面工作得非常顺利。
https://stackoverflow.com/questions/15412260
复制相似问题