Java Swing GUI程序启动时,JVM会启动多个线程,Swing并不是线程安全的,如果处理不当Swing程序会反应迟钝,JavaSE6开始引用SwingWorker能够改善Swing程序结构,提高界面的灵活性。
-
事件派发线程
当界面程序启动时,会调用界面的主方法
Java.awt.EventQueue.invokeLater(new Runnable(){
public void run(){
new NumberAddutionUI().setVisible(true);
}
}
invoketLater方法的意思是提交程序在事件派发线程(EDT)上执行其Runnable任务,此点是创建UI的点,也就是线程开始将控制权转交给UI的点。之后,主线程结束,程序在EDT中运行。由于EDT线程负责GUI组件的绘制和更新,所有事件处理都在EDT上进行,程序同UI组件和其基本数据的交互只允许在EDT上进行。由此可知EDT队列非常繁忙,几乎每一次GUI交互和事件都是通过它完成的。所以事件队列中的任务必须非常快,否则就会阻塞其他任务。因此,所有耗时的任务都不应该放在EDT上进行,同时Swing编程也要注意以下几点,1)从非EDT线程访问UI主键及其事件监听器会废纸界面更新和绘制错误。
2)从EDT上执行耗时任务线程会使程序失去响应,这会使GUI事件阻塞在队列中得不到处理。
3) 应使用独立的任务线程来执行耗时计算或输入输出密集型任务,想数据库通信,访问网站资源,读写大量数据的文件。
总之任何干好活延迟UI事件处理只应该在独立任务线程中;在主线程或任务线程中同Swing组件或其默认数据模式进行的交互都是非线程安全的。
-
SwingWorker类
-
SwingWorker类的定义
Swing Worker类能够帮助线程与Swing EDT之间的交互,有助于分离Swing EDT和任务线程。SwingWorker的使用能够使他们各负其责,对于EDT来说,就是绘制和更新界面,并响应用户输入;对于线程任务来说,就是执行和界面无直接关系的耗时任务和I/O密集型操作。
SwingWorker类的定义
当界面程序启动时,会调用界面的主方法public abstract calss SwingWorker<T,V>
extends Object implements RunnableFutureSwingWorker是抽象类,因此必须继承它才能执行所需的特定任务。该类对象产生类型为T的结果值以及类型为V的进度数据。
RunnableFuture是Runnable和Future两个接口的简单封装。
SwingWorker实现了两个父类接口大部分方法。
方法 功能 boolean cancel(boolean mayInterruptIfRunning) 取消正在进行的工作。 T get() 获取类型为T的结果值。该方法将一直处于阻塞状态,直到结果可用。 T get(long timeout,TimeUnit unit) 获取类型为T的结果值,将会一直阻塞直到结果可用或超时。 boolean isCancelled() 判断任务线程是否被取消。 boolean isDone() 判断任务线程是否完成。 abstract T doInBackground() 该方法作为线程的一部分执行,负责完成线程的基本任务,并以返回值(类型为T)作为线程的执行结果。继承类必须覆盖该方法并确保包含或代理任务线程的基本任务。不要直接调用该方法,应使任务对象的execute方法来调度执行。 protected void done() 在doInBackground()方法完成之后,SwingWorker在EDT上激活done方法。如果任务需要在完成后使用线程结果更新GUI组件或者做些清理工作,可覆盖该方法来完成. void publish(V…data) 传递中间进度数据到EDT。从doInBankground方法调用该方法。 void process(Listdata) 覆盖该方法处理任务线程的中间结果数据 void execute() 为SwingWorker线程的执行预订这个SwingWorker对象。 任务线程有几种状态:使用SwingWorker.StateValue枚举值来表示:PENDING、STARTED和DONE线程一旦创建就处于PENDING 状态,当doInBackground方法开始时,任务就进入STARTED状态,当doInBackground方法完成后,任务线程就出入DONE状态
任务对象有一个进度属性,随着任务进展时,可以将这个属性从0更新到100标识任务进度,当该属性发生变化时,任务通知处理器进行处理。 -
SwingWorker的工作模式
当Swing GUI 程序执行耗时任务时,在EDT中创建一个SwingWorker对象。在该对象编写有实现耗时任务代码的doInBackground方法中执行耗时操作,该方法在EDT中被使用execute方法调用,在SwingWorker线程中执行。在doInBackground方法中不时地调用public来发布中间数据。publish方法使得process方法在EDT中执行来处理进度数据。当工作完成时,在EDT中调用done方法以便完成UI的更新,在done方法中可以用get方法获取doInBackground的执行结果
-