[英]How do I code multithreading to speed up heavy, repetitive task?
我有一个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);
图像被依次装入并放入盒子中。 我想做多线程有两个困难
谢谢。
线程如何将值返回给父对象
使用回叫机制。 对于Swing,这意味着使用SwingWorker并通过worker的done()
方法或通过向该worker添加PropertyChangeListener来通知GUI线程完成情况,以侦听该工人的“ state”属性,以了解何时更改为SwingWorker.StateValue.DONE
如何实现无阻塞的回调,从而将图像顺序添加到框中
SwingWorker具有一个发布/处理方法对,该对允许通过publish方法从后台线程顺序发送数据,然后在process方法内的事件线程上顺序处理数据。 这需要使用SwingWorker<VOID, Image>
或SwingWorker<VOID, Icon>
或类似的东西,第二个通用参数指示通过此机制发送的对象的类型。
例如:
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
}
}
}
并在GUI中使用它:
// may need constructor to pass GUI into worker
final MyWorker myWorker = new MyWorker();
myWorker.addPropertyChangeListener(evt -> {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
// We're done!
// call get to trap errors
try {
myWorker.get();
} catch (InterruptedException | ExecutionException e) {
// TODO: real error handling needed here
e.printStackTrace();
}
}
});
myWorker.execute(); // start worker in a background thread
有关Swing并发的更多信息,请查看课程:Swing中的并发
多线程将加快应用程序的速度,但是我认为执行延迟加载是更好的方法(您可以同时执行)。 您不能同时显示所有这些图像,因此建议您加载在开始时可见的图像,然后根据需要加载图像,这将极大地提高性能并减少内存/资源的使用。
如果您确实要加载全部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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.