在EDT中运行时,显示JFreeChart点的性能问题

问题描述 投票:0回答:1

背景:

一个著名的Swing最佳实践要求是与Swing框架进行交互也必须在EDT中执行(事件调度线程)。

因此,我更改了代码以使基于JFreeChart的更新可以在EDT中运行。但是,一个完整的图表显示任务通常需要大约7分钟才能在“正常”线程上完成,而在EDT中运行则要花费几个小时!

我做错了什么?我是否误解了Swing并发课程?我真的必须在EDT中运行org.jfree.data.time.TimeSeries.addOrUpdate(date, double)吗?

请告知!

详细信息:

单击Swing GUI按钮,我的程序触发了一项耗时的任务。基本上,它读取具有对值(日期,双精度)的(大)文件,然后使用JFreeChart框架显示它们。

因为这是一项耗时的任务,所以在读取和显示数据时,JProgreessBar在前台显示用户进度状态,而在后台更新图表(用户仍然可以直观地看到每个图表更新,位于后台进度栏)。

这很好,直到我决定查看代码以更新图表数据并将其显示在Swing EDT中。然后,通常需要大约7分钟才能完成的完整任务开始需要花费几个小时才能完成!

这是我正在使用的线程列表:

1)由于任务是由Swing Button侦听器触发的,因此它正在EDT中运行。 JProgressBar也正在同一线程中运行;

2]当显示JProgressBar时,在后台创建并执行了第二个(“正常”)线程。这是繁重的工作。

[它包括另一个线程上的JProgressBar状态的更新(通过调用JProgressBar.setvalue())和我的JFreeChart图表的更新(通过调用TimeSeries.addOrUpdate(date, double),后者自动更新org.jfree.chart.ChartPanel)。

在我的第二个(“正常”)线程中更新图表通常需要大约7分钟才能完成。没有任何明显的问题。

但是,由于知道大多数Swing对象方法都不是“线程安全的”并且ChartPanel只是用于显示JFreeChart对象的Swing GUI组件,因此我决定在EDT中运行图表更新代码TimeSeries.addOrUpdate(date, double)

仍然在第二个“正常”线程中运行,我使用以下异步代码进行了测试:

javax.swing.SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        TimeSeries.addOrUpdate(date, double);
    }
});

但是我意识到在更新图表之前,我的JProgressBar将达到100%。我想这是可以预期的,因为显示图表数据比获取和处理数据要慢得多。

然后我尝试了以下同步代码:

try {
    javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
            TimeSeries.addOrUpdate(date, double);
        }
    });
} catch (InvocationTargetException | InterruptedException e) {
    e.printStackTrace();
}   

这是我发现性能问题的地方:现在,过去需要大约7分钟才能完成的完整任务,而要花几个小时才能完成!

所以,我的问题是:

我在做什么错?我是否误解了Swing并发课程?我真的必须在EDT中运行TimeSeries.addOrUpdate(date,double)吗?

请告知!

更新:完整的代码太大了,无法在此处显示,但是您可以在下面找到代码快照。也许,关于代码的唯一值得注意的事情是我使用了反射。这是因为我使用了一个通用的ProgressBar类,该类在后台调用我将其作为参数发送的任何类(尽管在下面的快照中并未清楚显示)。
//BUTTON LISTENER (EDT)
public void actionPerformed(ActionEvent arg0) {
    new Process_offline_data();
}


public Process_offline_data() {
    //GET DATA
    String[][] data = get_data_from_file();

    //CREATE PROGRESS BAR
    int maximum_progressBar = data.length;
    JProgressBar jpb = init_jpb(maximum_progressBar);

    //JDIALOG MODAL WINDOW
    JDialog jdialog = create_jdialog_window(jpb);


    Object class_to_invoke_obj = (Object) new Show_data_on_chart();
    String main_method_str = "do_heavy_staff"; 

    Runnable r = new Runnable() {
        public void run() {             

            //REFLECTION
            Method method = null;
            try {
                method = class_to_invoke_obj.getClass().getDeclaredMethod(main_method_str, JProgressBar.class, String[][].class);
            } catch (NoSuchMethodException | SecurityException e1) {
                e1.printStackTrace();
                jdialog.dispose();      //UNBLOCKS MAIN THREAD
                return;
            }

            try {
                method.invoke(class_to_invoke_obj, jpb, data);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
                e1.printStackTrace();
                jdialog.dispose();      //UNBLOCKS MAIN THREAD
                return;
            }
            //----------------


            jdialog.dispose();      //UNBLOCKS MAIN THREAD
        }
    };
    new Thread(r).start();
    //----------------


    //THIS IS STILL EDT
    jdialog.setVisible(true);       //BLOCKS HERE UNTIL THE THREAD CALLS jdialog.dispose();
}



public class Show_data_on_chart {
    public void do_heavy_staff(JProgressBar jpb, String[][] data) {

        TimeSeries time_series = get_TimeSeries();      //JFreeChart datamodel

        int len = data.length;
        for (int i=0; i<len; i++) {
            jpb.setValue(i+1);

            Millisecond x_axys_millisecond = convert_str2date(data[i][0]);
            Double y_axys_double = convert_str2double(data[i][1]);

            try {
                javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        //AUTOMATICALLY UPDATES org.jfree.chart.ChartPanel
                        time_series.addOrUpdate(x_axys_millisecond, y_axys_double);
                   }
                });
            } catch (InvocationTargetException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

背景:一个众所周知的Swing最佳实践要求是,与Swing框架进行交互的代码也必须在EDT(事件调度线程)中执行。因此,我将代码更改为...

java multithreading swing jfreechart edt
1个回答
0
投票

这是我解决更新图表的方法。

© www.soinside.com 2019 - 2024. All rights reserved.