如何安全使用SWT的显示器asyncExec

大多数用户界面(UI)工具包都是单线程的, SWT也不例外。 这意味着必须仅从单个线程(即所谓的UI线程)访问UI对象。 另一方面,应在后台线程中执行长时间运行的任务,以使UI保持响应。 这使得后台线程需要排队在UI线程上执行更新,而不是直接访问UI对象。

为了安排代码在UI线程上执行,SWT提供了Display asyncE‌xec()和syncE‌xec()方法。

显示asyncE‌xec与syncE‌xec

虽然这两种方法都将参数放在队列中以便在UI线程上执行,但是它们在执行(或不执行)之后的操作不同。 顾名思义,asyncE‌xec()异步工作。 它在可运行变量入队后立即返回,并且不等待其执行。 而syncE‌xec()处于阻塞状态,因此确实要等到代码执行完毕。

根据经验,只要不依赖计划代码的结果即可使用asyncE‌xec(),例如仅更新小部件以报告进度。 如果计划的代码返回了与进一步控制流相关的内容(例如,在阻止对话框中提示输入),那么我将选择syncE‌xec()。

例如,如果后台线程想要报告已完成工作的进度,则最简单的形式可能如下所示:

progressBar.getDisplay().asyncE‌xec( new Runnable() {
  public void r‌un() {
    progressBar.setSelection( ticksWorked );
  }
} );

asyncE‌xec()计划“在下一个合理的机会”(如JavaDoc所说)在UI线程上执行可运行对象。

不幸的是,上面的代码可能会不时地失败,并会出现一个放置小部件的异常 ,或更确切地说是一个SWTException,其代码== SWT.ERROR_WIDGET_DISPOSED。

因此,原因是,进度条在被访问时可能不再存在(即,调用setSelection())。 尽管我们仍然保留着对小部件的引用,但是由于小部件本身已被废弃,因此并没有太大用处。 解决方案显而易见:代码必须首先测试该小部件是否仍然存在,然后再对其进行操作:

progressBar.getDisplay().asyncE‌xec( new Runnable() {
  public void r‌un() {
    if( !progressBar.isDisposed() ) {
      progressBar.setSelection( workDone );
    }
  }
} );

看起来很明显,一次又一次地执行这种检查是很乏味的。 您可能想在Eclipse bugzilla中搜索“ widget处置”,以了解此问题的发生频率。 因此,我们提取了一个封装检查的辅助类。

new UIThreadSynchronizer().asyncE‌xec( progressBar, new Runnable() {
    public void r‌un() {
      progressBar.setSelection( workDone );
    }
  } );

UIThreadSynchronizers asyncE‌xec()方法期望将小部件作为其第一个作为上下文的参数。 上下文小部件是指如果可运行的部件多于一个,则将受可运行部件或合适的父部件影响的部件。 在运行runnable之前,将检查上下文小部件。 如果仍然有效(即未处置),则将执行代码,否则,将静默删除该代码。 尽管忽略已处置小部件的代码的行为可能看起来很粗心,但它适用于到目前为止我们遇到的所有情况。

进行线程间通信的单元测试代码特别难以测试。 因此,尽管UIThreadSynchronizer是无状态的,但必须对其进行实例化以使其可以通过test double替换。

尽管示例使用了asncE‌xec(),但UIThreadSynchronizer也支持syncE‌xec()。 并且,当然,helper类也与RAP / RWT兼容。

如果您完整地阅读了源代码,您可能已经注意到可能存在争用情况。 因为Widget类的所有方法都不是线程安全的,所以isDisposed()或getDisplay()返回的值可能是陈旧的(请参见第51 第60行 )。 当时故意将其忽略-阅读:我没有找到更好的解决方案。 尽管runnable可能会被错误地排入队列,但是isDisposed()-check(在UI线程上执行)将最终阻止代码执行。

剩下的线程问题还有另一个(绝对是很小的)机会:恰好在调用(a)syncEecxec()之前,检查显示器的处置方式,以免发生小部件处置异常。 但是,如果将显示放置在检查和(a)syncE‌xec()的调用之间,则可能会发生这种情况。 尽管可以通过将调用包装到忽略小部件处理的异常的try-catch块中来解决asyncE‌xec()的问题,但对syncE‌xec()而言,相同的方法将失败。 无法通过合理的努力将可运行对象引发的SWTException与syncE‌xec()引发的SWTException区别开来。

翻译自: https://www.javacodegeeks.com/2014/09/how-to-safely-use-swts-display-asyncexec.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值