【Swing入门教程】一步一步做Netbeans(5):Swing的线程管理及如何写健壮的安全的正确的Swing程序

     又过了12点。N天前在china-pub订的两本书经过漫长的等待今天终于到手了:《 Core Java, Vol. 2: Advanced Features 》和《 Filthy Rich Clients 》。这年头,快递都涨价了速度倒没见快哪去。最近有点急躁,没事,每月都有那么几天,哦,别误会,我是说男性生理周期。

     至本教程,我们一直都只是做些界面或组件,没过多考虑程序结构和逻辑的问题。事先也声明了,只是做界面,不管逻辑。逻辑可以不做,但是程序的结构可不能乱来,这样会误人子弟。回到教程4,其中有一部是初始化文件树,我们把这段放到界面初始化完并显示后再做,看看效果怎样;这样的话得改一下,给JTree声明了DefaultTreeModel,并增加了一个自定义的状态栏StatusBar(代码放在后面):

       JTree初始化部分也修改一下:

      initTree()也跟着修改一下,addDir()方法不变:

     我们想让主界面出来后再初始化文件树:

     运行后会出现什么效果呢?预期是界面出现后出现进度条初始化文件树,完成后进度条隐藏。而实质上是主界面出现后卡了大概3秒钟后文件树出现,却没发现进度条。刚学Swing时我也是大骂这JProgressBar怎么不好用啊。要知道这为什么,你就需要了解一下Swing的单线程模式了。

     一:EDT

     无论什么时候,运行一个Swing应用程序都会自动创建三个线程。一是主线程,它运行着应用程序的主方法。二是工具包线程,负责捕获系统事件,它不会运行应用程序的代码,捕获的事件会发送到第三个线程EDT(Event Dispatch Thread,事件派发线程)。

     EDT与Swing的交互算是最密切的了。它负责把事件派发到适当的组件并调用它们的绘制方法,正是由于此,我们才会看到一个变化着的界面。可以这样说,AWT和Swing中的任何事情的进行都或多或少和EDT有关。

     单线程,队列,你有点眉目了吗。当我们再EDT中执行一个耗时较长的操作时,界面就刷新不过来了,因为刷新部分还在排队。我们以上的程序正是由于此而造成卡3秒的。以前看Swing组件的javadoc时都会看到这样的一句话:Swing 不是线程安全的。有关更多信息,请参阅 Swing's Threading Policy 。那时我还也真是莫名奇妙。

     二:SwingUtilities

     知道问题所在就好办了,既然耗时操作不能放到EDT中,那就放到一个新的线程中去吧:

      运行时没出现什么问题,进度条也能显示,看似一切都正常。不过它违反了Swing的单线程规则:修改组件的状态要在EDT中进行。测试时可能没引起任何问题,但随时都有可能出现死锁。这个我是深有体会,自己开发的编辑器逻辑是没什么问题,就是跑着跑着就出现一些莫名其妙的异常来,并且根据异常信息看似和自己写的代码半毛子的关系都没有。

      尝试用Swing的工具类SwingUtilities中的invokeLater(),它可以用于EDT中发布一个新任务。一般Netbeans自动生成的代码中都会用该方法初始化Swing组件。把initData()改成这样:

三:SwingWorker

      SwingUtilities是很有用,不过它要创建不少匿名Runnable类,但要做的事情多且繁琐时SwingUtilities写的代码就难于阅读和维护了。这时不妨考虑下SwingWorker,这可是Java SE 6中新加的哦。它可以在一个后台线程中运行一个特定的任务,在EDT上发布任务进行的中间结果和最终结果,关于SwingWorker的具体用法请查看javadoc吧,我困得不行了。下面给出构造文件树的SwingWorker的实现:

      要运行它,将NetbeansUI类中的38行改为:

搞定,哦,还不能收工。附上StatusBar类的代码:

猜你喜欢

转载自blog.csdn.net/monitor1394/article/details/6214536