RCP中异步线程的处理 (转)

在RCP中要在非UI线程中执行UI线程的操作,最简单的方式就是display.syncExec或者display.asyncExec,如果UI线程所需的时间较长的话,则应该使用display.asyncExec

在执行异步线程的时候,我们一般应当继承Job或者UIJob类:UIJob是在UI线程中运行的,可以直接访问窗体组件。Job是在非UI线程中运行,如果在里面想访问窗体组件,需要通过Display.asynExec()或者synExec方式来执行。UIJob要尽量的短,不要过多的占用UI线程的时间。

在我现在的系统中,每当UI需要和Server交互的时候,都需要检测Server是否启动,如果未启动的话,尝试启动三次,三次不成功则抛出Exception,用 MessageDialog给用户提示,启动成功以后,还需载入相关信息。这样的异步线程,就只能放到Job中执行。

然而,这样还是远远不够的,试想一下,如果点完一个MenuItem以后,过了很久才会有所反应,这种用户体验岂不是糟糕透了?于是我们还要提供进度条来提高用户体验度,在RCP中,就是如下的代码:

1. ProgressMonitorDialog progress = new ProgressMonitorDialog(null);
2. progress.setCancelable(true);
3. try {
4. progress.run(true, true, new IRunnableWithProgress() {
5. public void run(IProgressMonitor monitor)
6. throws InvocationTargetException {
7. doSomething();
8. }
9. });
10. } catch (InvocationTargetException e) {
11. e.printStackTrace();
12. } catch (InterruptedException e) {
13.
14. }


第二行中的progress.setCancelable(true)是为了允许客户在长时间执行后台进程的时候,可以取消掉进程的执行。这里我把实际的执行过程Extract了出来,免得方法太长,doSomething()看起来应该是这样子的:

1. public void doSomething(IProgressMonitor monitor) {
2. monitor.beginTask("Beginning...", IProgressMonitor.UNKNOWN);
3. monitor.subTask("Doing first job");
4. doFirstThing();
5. if(monitor.isCanceled()) return;
6. monitor.worked(1);
7. monitor.subTask("Doing second job");
8. doSecondThing();
9. if(monitor.isCanceled()) return;
10. monitor.worked(2);
11. ......
12. monitor.done();
13. }
14. }


这样子当用户点击ProgressMonitor的Cancel按钮时,monitor.isCanceled()就会返回 true,doSomething便中止执行。

说到这里,可能就会有疑问了,monitor.isCanceled()方法只会在doFirstThing()和doSecondThing()之间才会被触发,那么如果doFirstThing()的过程中有异常情况而导致无法返回,那点击Cancel就根本没有作用啊?

唔......这个就是问题的核心所在了,我不知道别人是如何解决的,在这里我只说一下我的解决方案,希望能够起到抛砖引玉的作用:

在前面已经提到,我使用了Job来处理异步线程,然而Job是通过调用job.schedule来执行的,用户无法确保job被执行的时机以及何时结束,一般的方法是使用Listener,Observer或者某个信号量来指示Job的结束。在有些地方我用的是Observer模式,而在这种情况下,我用的是boolean变量来做指示。于是,上面的doSomething就变成了:

1. public void doSomething(IProgressMonitor monitor) {
2. monitor.beginTask("Beginning...", IProgressMonitor.UNKNOWN);
3. monitor.subTask("Doing first job");
4. job.schedule();
5. while (!jobFinished) {
6. if (monitor.isCanceled()) {
7. logger.info("monitor is canceled");
8. job.cancel();
9. return;
10. }
11. monitor.worked(times);
12. times++;
13. }
14. monitor.done();
15. }
16. }


这样,只要while循环没有满足结束条件,我们就可以通过点击Cancel按钮来cancel掉Job。如果job中还有些东西是无法自动cancel 掉的话,比如Socket通信等,我们还可以在job.cancel()前面加上一些代码来做这样的工作,比如 job.getSocket().close()等,当然还要处理好各种Exception。

在Eclipse的Article里面,有几篇分别讲述Job和ProgressMonitor的文章,很是详细,有兴趣的朋友不妨找来看看。不过文章只是讲解原理性的东西,开发中所碰到的问题,还是要靠个人的经验来分析解决......所以,还是多多coding,多多thinking,提高解决实际问题的能力吧:)

转自JavaEye社区http://www.iteye.com/post/275070
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值