SWT中定时器的一种特殊实现方式/SWT中线程互访时display.asyncExec/display.syncExec...程序死掉无响应的解决办法...

最近在研究SWT,写了个小例子,涉及到线中的数据互访,如果在一个线程中的触发事性中再去访问另一个线程的数据,会把Invalid thread access的错误。

用SWT提供的display.asyncExec方法,发现其实质根本不是另开一个线程,只是把run方法调用了一次,所以导致调用Thread.sleep时程序就会死掉。

经过查阅资料及baidu和google,找到了解决办法,现总结一下:

1、定时器实现方式,在Main方法中加一个定时器,代码如下:()

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; public class Main { Text text = null; public Main() { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(200,60); text = new Text(shell,SWT.BORDER); text.setBounds(0,0,200,20); shell.open(); final Runnable timer = new Runnable () { int count = 0; public void run () { synchronized (this) { try { text.setText( Integer.toString(count++)); } catch (Exception e) { e.printStackTrace(); } } } }; while (shell != null && !shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); else display.timerExec(500,timer); } } public static void main(String[] args) { new Main(); } }

2、但有时候并不一定要程序执行时就要定时检测,有时需要外部事情激发这就出现了第2种解决方案,写一个内置类,可以放在事件监听的方法中,然后激发:

import org.eclipse.swt.widgets.*; public class Main { private static int counter; public static void main(String[] args) { final Display display = new Display(); final Shell shell = new Shell(); shell.setText("SWT Application"); shell.open(); new Thread(new Runnable() { public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) {} display.asyncExec(new Runnable() { public void run() { shell.setText("" + counter++); } }); } } }).start(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } } }

3、第二种方法虽好,可是创建了不少对象,对程序优化一下,可以得到更好的一种解决方案(比第二种方法少创建一个对象):

import org.eclipse.swt.widgets.*; public class Main { private static int counter; public static void main(String[] args) { final Display display = new Display(); final Shell shell = new Shell(); shell.setText("Counter"); shell.open(); new Thread() { private Runnable cmd = new Runnable() { public void run() { shell.setText(String.valueOf(counter++)); } }; public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e) { return; } display.asyncExec(cmd); } } } .start(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } } }

顺便再说一下display.asyncExec和display.syncExec的区别:

SWT组件Diaplay提供syncExec与asyncExec方法,其原型为:syncExec (Runnable runnable),asyncExec (Runnable runnable),Runnable的run方法中可以封装要执行的代码,一般而言是UI相关的代码,如更新组件显示、刷新状态等。Diaplay是和线程关联的,其所在的线程一般称谓UI线程,可以有多个UI线程,每个UI线程一个Diaplay。所有的SWT组件相关代码,必须在UI线程之中执行。

syncExec与asyncExec相同点,都是为了让Runnable封装的代码在指定的Diaplay(比如某个产成Image的diaplay) 相关的UI线程中执行。如:imgCreateDiaplay.asyncExec(runnable)。需要说明的是,当前线程一般是非UI线程,也可以是UI线程(如其它UI相关线程如awt UI线程,和为提高执行效率,多个SWT UI线程之间协作并发执行,甚至调用线程和执行runnable的UI线程是同一个线程)

syncExec与asyncExec不相同点体现在对方法调用线程本身的影响,syncExec阻塞当前线程直到UI线程完成runnable中的代码执行;而asyncExec则直接返回,不等待runnable中代码被执行,但并不是说asyncExec执行的代码一定不在同一个线程中,有些时候是同一个线程,只不过将代码的执行根据需要分成两个部分或多个部分处理。

两者的异同决定了其分别适应不同的场合,一般syncExec适合在需要同步UI更新之后继续执行的代码,asyncExec适合在不便、不能syuncExec的情况下使用。

syncExec适用情况比较简单,以下总结asyncExec的适用情况。

1、非UI线程需要调用在UI线程中调用的组件方法。非UI线程是相对与UI线程来讲的,UI线程准确的讲是diaplay变量所在的线程,因此非UI线程其实是非display所在的线程,其可以是任何其它线程,如UI无关的后台作业处理线程、SWT-AWT共用应用中的awt所在线程、其它 display线程(这种情况比较少,一般应用于服务程序,如大量生成图片的多UI线程,相互之间协调时的调用,如几个UI线程负责地图图片的绘制,然后交给另外一个UI线程做装饰处理);

2、跳出当前UI事件处理,安排后续事件。当前display所在的UI线程,在事件处理过程中,需要在执行完毕之后启动另外一个UI处理过程,可以使用 asyncExec,发起另外一个UI线程处理,结束当前的UI处理。有几种情况下需要这么做:A、当前事件处理必须执行完毕,使应用到达一定的状态之后,做另外的UI处理,但是由于SWT、JFace或其它应用框架的存在,当前事件处理完成之后需要应用框架执行一些其它代码之后才可以执行另外的UI处理,否则会导致状态不一致,界面出错。但是当前事件处理完毕之后,不会出现其它事件来触发需要另外执行的代码,此时可以使用asyncExec,在框架的事件处理序列中插入另外一个事件,在当前事件处理完毕之后的某个时刻(一般很快)来执行;B、定时刷新或其它不是很重要的UI操作,通过 asyncExec执行,不影响重要的UI事件处理。asyncExec所在的事件队列优先级较低。

3、事件比较密集,而且不均衡,有时非常密集,有时不太密集,为了将事件处理均衡处理,使UI线程始终能够应付自如,而不是延迟重要事件的处理、使用户感到界面迟钝现象,将不重要的事件放到低优先级序列中,从而保证用户响应性,界面整体的有效性。

asyncExec使用时需要注意的问题主要在于两个方面。
1、响应及时性。可以认为SWT存在两个事件队列,正常UI事件队列,需异步处理的队列,该队列优先级较低,asyncExec对应于SWT低优先级队列,因此有可能在正常队列事件较多、事件处理较慢的时候,asyncExec相关代码不能及时执行的问题,从而导致响应不够及时;
2、多线程同步问题。假如某段事件处理代码发出多个asyncExec请求,每个asyncExec代码访问同一个变量,假设该变量是整数,第一次发出请求是值为1、第二次为2、第三次为3,所有请求发出,该事件处理完毕时,整数值为5,随后第一次发出的asyncExec请求执行,访问整数变量,此时为 5,而本应该是1,其它几个有类似问题。


当然了,Display也提供了timerExec,可以将其理解为Timer和asyncExec两者的结合,代码在指定时间之后异步执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值