摇摆“阻塞”,我想我需要线程,但不知道多少

时间:2010-01-30 06:44:08

标签: java swing multithreading

我有一个小的Java应用程序来有效地“拖尾”在ini文件中定义的任意文件集合。我的“LogReader”类扩展了JFrame,并完成了繁重的工作;将文件路径集合读入矢量,然后迭代矢量,读取每个文件并将每个文件的最后X行添加到JTabbedPane选项卡上的文本区域。通过ActionListener单击JButton来启动构建向量和迭代文件的过程。

文件的读取工作正常(现在仍然如此),但是阅读20个文件的过程需要花费一些时间,有些文件长达30MB。为了帮助传递那段时间,我决定添加一个进度屏幕,其中显示“正在读取文件#3 of 26:c:\ logs \ superduper1.log”,依此类推。所以我创建了另一个类“SplashScreen”,也扩展了JFrame,并添加了一个表明进度的JLabel。 SplashScreen类有一个update()方法,它只在JLabel上执行setText()。

JButton上的ActionListener调用RefreshLogs(),它看起来像:

vctFileStrings.clear();
tpMain.removeAll();
frmSplash.update("Loading Configuration"); //Update the label on the Splash Screen instance
BuildVectorOfLogs(strConfFile); //Read the collection of files into the vector
frmSplash.update("Reading Logs");
ReadLogs(); //read the files, updating the Splash Screen as we go

然后ReadLogs()迭代向量,读取文件并构建TabbedPane。

但我注意到,当从ActionListener中调用RefreshLogs()时,Splash Screen不会更新。但是,如果我将RefreshLogs()添加到第一帧的构造函数中,则启动屏幕将按预期工作(更新每个文件的进度)。经过一些实验和阅读后,我认为我需要创建一个读取文件的工作线程,同时更新事件调度队列中的启动画面。

我的问题是:
- 我的想法是否正确?是否有一些简单的替代方法可以实现线程,从而允许我从ActionListener调用的方法更新闪屏? - 如果使用线程最好地完成这项工作,我需要在哪个活动范围内进行线程化?我是否需要将所有文件I / O活动放入自己的线程中?我应该将GUI活动(标签更新)放在他们自己的线程中,以便它们与JButton点击事件分开进行吗?

3 个答案:

答案 0 :(得分:4)

我会说:是的,您对将大文件的读取卸载到单独的线程的想法是正确的。您永远不应该在事件调度线程上执行长任务,因为当该线程忙时,GUI将无响应,并且您的应用程序会感觉很慢。

SwingWorker这听起来很好。此类允许您在单独的线程上执行慢速请求(例如磁盘或网络访问),并使用EDT将进度更新反馈到GUI。 SwingWorker负责管理线程之间切换的所有复杂性。您所要做的就是在适当的位置实现您的业务逻辑。

Sun有a tutorial on SwingWorker

答案 1 :(得分:3)

是的,你应该把时间紧张地放在一个单独的线程中。现在,您可以在事件调度线程(EDT)中执行所有操作,该线程将更新您的GUI,但正忙于读取您的数据。

您可以使用SwingWorker。看看Using a Swing Worker Thread看起来像你需要的那样。

答案 2 :(得分:0)

有一个建议,要弄清楚如何执行此操作,以及在使用NetBeans或有权访问NetBeans的情况下,请查看默认的Java Desktop Application template。它创建了一个预先连线的桌面应用程序,其状态栏内置了进度条,当执行任何“操作”代码时,它会自动更新。它利用Action API,它也预先连接在后台线程中运行。

通过查看自动生成的代码,您将能够在自己的代码中正确轻松地实现它。