如何编写多线程代码以加快繁重的重复任务?

时间:2019-04-30 12:29:32

标签: java swing

我有一个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);

图像被加载并顺序放入盒子中。如果要多线程,我有两个困难

  1. 线程如何将值返回给父对象
  2. 如何实现将图片添加到 依次框

谢谢。

3 个答案:

答案 0 :(得分:2)

  

线程如何将值返回给父级

使用回叫机制。对于Swing,这意味着使用SwingWorker并通过工作器的done()方法或通过向工作器添加PropertyChangeListener来通知GUI线程完成,以侦听工作器的“ state”属性,以了解何时更改为{{ 1}}

  

如何实现将图片依次添加到框中的无阻塞回调

SwingWorker具有一个发布/处理方法对,该对允许通过publish方法从后台线程顺序发送数据,然后在process方法内的事件线程上顺序处理数据。这要求使用SwingWorker.StateValue.DONESwingWorker<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();