我有一个swing应用程序,启动起来很慢,因为它必须将一千张图片加载到GUI中。启动需要10秒钟。
这是一个单线程应用程序,如何编码多线程以加快任务速度?以下代码处于1000次迭代的for循环中。
ImageIcon icon = new ImageIcon(Files.readAllBytes(coverFile.toPath()));
// ImageIcon icon = createImageIcon(coverFile);
JLabel label = null;
if (coverCount % 2 == 0) {
label = createLabel(coverFile, movieFile, icon, SwingConstants.LEFT);
} else {
label = createLabel(coverFile, movieFile, icon, SwingConstants.CENTER);
}
box.add(label);
图像被加载并顺序放入盒子中。如果要多线程,我有两个困难
谢谢。
答案 0 :(得分:2)
线程如何将值返回给父级
使用回叫机制。对于Swing,这意味着使用SwingWorker并通过工作器的done()
方法或通过向工作器添加PropertyChangeListener来通知GUI线程完成,以侦听工作器的“ state”属性,以了解何时更改为{{ 1}}
如何实现将图片依次添加到框中的无阻塞回调
SwingWorker具有一个发布/处理方法对,该对允许通过publish方法从后台线程顺序发送数据,然后在process方法内的事件线程上顺序处理数据。这要求使用SwingWorker.StateValue.DONE
或SwingWorker<VOID, Image>
或类似的东西,第二个通用参数指示通过此机制发送的对象的类型。
例如:
SwingWorker<VOID, Icon>
并在GUI中使用它:
public class MyWorker extends SwingWorker<Void, Icon> {
@Override
protected Void doInBackground() throws Exception {
boolean done = false;
while (!done) {
// TODO: create some_input here -- possibly a URL or File
Image image = ImageIO.read(some_input);
Icon icon = new ImageIcon(image);
publish(icon);
// TODO: set done here to true when we ARE done
}
return null;
}
@Override
protected void process(List<Icon> chunks) {
for (Icon icon : chunks) {
// do something with the icon here
// on the event thread
}
}
}
有关Swing并发的更多信息,请查看Lesson: Concurrency in Swing
答案 1 :(得分:0)
多线程将加快应用程序的速度,但我认为执行延迟加载是一种更好的方法(您可以同时执行两者)。您不能同时显示所有这些图像,所以我建议您加载一开始就可见的图像,然后根据需要加载图像,这将极大地提高性能并减少内存/资源的使用。>
答案 2 :(得分:0)
如果您真的要加载全部1000张图像:
使用一个后台线程就足够了,这样就不会降低主Swing Event循环线程的速度。
创建一个实现可运行的自定义类,该类具有对所有上下文的引用以完成此工作。像这样:
public static class IconLoader implements Runnable{
private List<File> movies;
private File coverFile;
private JPanel box;
public IconLoader(JPanel box, File coverFile, List<File> movies) {
this.box = box;
this.coverFile = coverFile;
this.movies = movies;
}
@Override
public void run() {
for(int coverCount=0;coverCount<movies.size();coverCount++) {
try {
final JLabel label;
File movieFile = movies.get(coverCount);
ImageIcon icon = new ImageIcon(Files.readAllBytes(coverFile.toPath()));
// ImageIcon icon = createImageIcon(coverFile);
if (coverCount % 2 == 0) {
label = createLabel(coverFile, movieFile, icon, SwingConstants.LEFT);
} else {
label = createLabel(coverFile, movieFile, icon, SwingConstants.CENTER);
}
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
box.add(label);
}
});
}catch(IOException e) {
e.printStackTrace();
}
}
}
private JLabel createLabel(File coverFile, File movieFile, ImageIcon icon, int direction) {
//Create the label and return
return null;
}
}
然后通过将可运行项传递到新线程并启动线程,在应用初始化期间开始加载过程。像这样:
new Thread( new IconLoader(box, coverFile, movies) ).start();