Event System事件系统【SWING监听事件的线程问题】

时间:2022-10-18 20:57:08

Event System事件系统

一个事件要求特定的动作被执行,它被作为消息由外界或系统自身发送给GUI系统。这些事件包括来自计算机设备如鼠标键盘和网络端口的I/O中断,以及GUI系统的逻辑事件触发,比如一个按钮的ActionEvent事件。

Single-Threaded vs Multiple-Threaded 单线程 vs 多线程

事件分发遵循两种不同的模型。单线程分发模型和多线程分发模型。

Event System事件系统【SWING监听事件的线程问题】

     在单线程分发模型中,一个事件从队列中抽出并在同一个线程中被立即处理。事件处理后,紧跟着的下一个事件再被抽出并继续下一轮的循环。在多线程分发模型中,从队列中获取事件的线程启动另一个被称作任务线程的线程,并把事件交给它处理。而获取事件的线程并不等待处理线程的结束。它简单的获取下一个线程并分发它。

     事件处理通常涉及应用程序的数据变化。而且这些数据经常是组件需要显示的。多线程分发很容易产生同步问题,它产生多个可能互相干扰的事件处理线程。在一个稳定的GUI系统中,组件应该能够保持视图与模型间的同步。由于同步问题的出现,多线程模型要求开发者拥有更多并发编程的经验。而对于普通编程人员,造成同步错误是很容易的。因此许多GUI系统并不使用这一模型。

    单线程模型通过强制事件序列化地被处理提供了实际上的同步。AWT,SWT和Swing 都采用了这一模型来分发事件。但单线程模型也会有它自己的问题。其中之一就是线程专注。既然所有的事件都在一个线程中被分发,如果其中的一个事件的处理费时过久,将会拖延下一个事件的抽取和执行。如果有一个PAINT事件被延后,那么在屏幕上就会呈现为无法响应。这经常使用户感觉到软件很慢。许多这样的低效程序是由于开发者的经验不足造成的。他们的做法是将耗时任务填充到监听器方法中。由于这种错误的编程方式在Swing中大量被使用而尤为突出,这也是它慢而丑陋的坏名声的由来之一。实际上,如果你懂得使用线程,Swing应用程序可以表现出很高的响应度。

Thread Safety线程安全

     上述问题的解决方案是启动一个单独的工作者线程来完成耗时处理,这样就能把事件分发线程释放处理以继续运作。如多线程模型中所做的那样,然而这同样会引入在多线程模型中出现的同步问题。许多GUI工具集都有自己先天性的机制来解决这一问题,例如,在组件树上的组合锁。开发者不需要为如何安全编程而操心。这样的工具集被成为线程安全的。AWT就是其中之一。

     然而,由于不必要的同步使得建立这样的GUI系统过于负责并造成了额外的开销。因此,Swing和SWT被设计为非线程安全的,这意味着开发者必须谨慎地实现他们的多线程任务。SWT和Swing在运行时线程安全行为上有一个小小的区别。SWT总是检查改变组件的操作是否在事件分发线程上执行。这样,开发者就能够发现同步问题。而Swing不这样,这是Swing的一个不知之初,这其实并不难实现。

Event Dispatching Thread事件分发线程

     AWT读取操作系统中的基本事件并在java代码中处理它们。AWT事件分发线程被命名为?AWT-{OS}-Thread。这个线程由AWT系统隐式启动。当AWT应用程序启动时,这个线程在背后启动,在操作系统上抽取和移除事件。当诸如按钮动作这样的逻辑事件被触发时,它传递给注册在按钮上的操作监听器。开发者也能为AWT组件编写鼠标,键盘和绘制事件的事件监听器。这通常通过扩展AWT Canvas组件来完成。这一组件支持了所有已提供的事件,而且你可以通过重写事件处理方法,实现一个自定义的组件。

     然而,在Swing中,这是一个不同的线程。Swing把AWT事件作为自身事件系统的一个输入。它获取AWT事件并做一些初始化处理,产生一个对应的Swing事件并把它放到自己的事件队列上。Swing也有自己的事件分发线程,通常命名为EventQueue-0。这个线程从事件队列中抽取Swing事件,就如同AWT从操作系统中抽取那样。然后它把事件分发给目标组件。通常事件首先被分发给组件的顶层容器,然后由顶层容器的dispatch方法处理,它可能被再分发或重定向到一个Swing组件,在那里继续由自己的监听器进行处理。

     例如,当一个鼠标移过一个JButton或JFrame时,一个指向JFrame的AWT事件在AWT线程上触发。AWT线程检查它是否需要作更多的处理,然后把它包装成一个Swing的MouseEvent对象并把它添加到EventQueue队列中。当获得MouseEvent事件后,EventQueue-0抽取这个事件并判断出目标Swing组件。这里,这个组件是JButton。然后它产生了一个包含相对坐标位置和事件源的新的MouseEvent重定向到这个JButton上,然后调用这个JButton的dispatch以继续分发。JButton的dispatch过滤事件给特定的方法最终实现由鼠标监听器在该点上的分发的点击。

     SWT更类似于AWT。唯一的区别是它要求开发者显式地书写事件循环代码。然而底层的实现细节是不同于AWT的。看看SWT的读取和分发事件代码,它会让你想起MFC的代码风格。

转载自:http://blog.csdn.net/zhenshiyiqie/article/details/7604689