Swing 线程安全样板
为了简单起见,想象一个下载文件的应用程序。有一个简单的 GUI,带有一个显示进度的标签。为了避免 EDT 违规,像每个合法公民一样,我在一个线程(主线程)中下载文件,并在另一个线程(EDT)中更新 GUI。所以,这里是相关的伪代码块:
class Downloader {
download() {
progress.startDownload();
while(hasMoreChunks()) {
downloadChunk();
progress.downloadedBytes(n);
}
progress.finishDownload();
}
}
class ProgressDisplay extends JPanel {
JLabel label;
startDownload() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Download started");
}
});
}
downloadedBytes(int n) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Downloaded bytes: " + n);
}
});
}
finishDownload() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Download finished");
}
});
}
}
我喜欢 Java 不支持闭包这一事实,而且代码对我来说非常清晰。抛开笑话不谈,我想知道……我做错了吗?是否有可能使用 SwingUtilities
、每个方法中 Runnable
的匿名实现等消除所有这些丑陋的样板?
我的情况比这稍微复杂一些,但我试图不通过实现代理或类似的东西来过度设计。
For the sake of simplicity, imagine an application that downloads a file. There is a simple GUI with one label that displays progress. To avoid EDT violations, like every lawful citizen I download the file in one thread (main), and update GUI in another (EDT). So, here's the relevant chunk of pseudcode:
class Downloader {
download() {
progress.startDownload();
while(hasMoreChunks()) {
downloadChunk();
progress.downloadedBytes(n);
}
progress.finishDownload();
}
}
class ProgressDisplay extends JPanel {
JLabel label;
startDownload() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Download started");
}
});
}
downloadedBytes(int n) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Downloaded bytes: " + n);
}
});
}
finishDownload() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
label.setText("Download finished");
}
});
}
}
I love the fact that Java does not support closures and the code is crystal clear to me. Jokes aside, I'm wondering... Am I doing it wrong? Is it possible to eliminate all this ugly boilerplate with SwingUtilities
, anonymous implementation of Runnable
in every method etc.?
My case is slightly more complicated than this, but I'm trying not to overengineer by implementing proxies or something like that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有一个用于该任务的特殊类:
SwingWorker< /代码>
。它允许您在单独的线程中运行代码并在工作结束时更新 UI。
There is special class for that tasks:
SwingWorker
. It allows you yo run code in a separate thread and update UI on the end of the work.如果不在其他地方引入大量冗余代码,您无法做太多事情来避免样板代码。但是您可以通过一个小的抽象帮助器类和一些不寻常的格式使其变得更好一点。
代码格式的目的是强调这一行中的所有代码基本上都是无趣的样板代码,可以轻松安全地复制到其他需要的地方。我们已经使用这种格式样式有一段时间了,结果证明它非常有用。
There is not much you can do to avoid the boilerplate code without introducing a lot of redundant code elsewhere. But you can make it a little bit nicer with a small abstract helper class and some unusual formatting.
The code formatting is meant to emphasize that all the code in this single line is basically uninteresting boilerplate code that can easily and safely be copied to other places where it is needed. We have been using this formatting style now for a while and it turned out quite useful.
我会使用类似的辅助方法。
I would use a helper method like.
几年前,我们在一个项目中使用了 Spin。
We used Spin in a project a few years back.
只是一个原始想法:
还没有尝试过,但我想当从 EDT 调用
setText()
时,将使用super
;但是当涉及其他线程时,重写的 (ThreadSafeJLabel.setText()
) 将稍后调用,这次是在 EDT 内。Just a raw idea:
Haven't tried it but I guess when called
setText()
from EDT,super
will be used; but when other thread is involved, the overridden (ThreadSafeJLabel.setText()
) will be called later, this time inside EDT.