`
Jameslyy
  • 浏览: 386713 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Eclipse 运行时概述 Part 3 —— 并行框架

阅读更多

并行框架(Concurrency infrastructure) 

        一个复杂系统的主要挑战之一就是在运行任务时能够保持能够响应的状态,当没有被设计在一起运行的组件共享相同的资源时,在扩展系统的挑战更大。org.eclipse.core.runtime.jobs 包用于解决这个问题,这个包提供了用于调度、执行和管理并行运行操作的基础工具,这个基础工具基于使用 jobs 表示一个能够异步执行的工作单元。

 

1. 作业(job)

        Job 类表示一个和其他作业并行运行的工作单元,要执行一个任务,插件创建一个作业并调度它。 一旦调度作业,会被加入到一个平台管理的作业队列中,平台使用一个后台调度线程管理所有挂起的作业 。当一个运行的作业结束时,将会被移出队列,平台决定下一次运行哪一个作业 。当作业 处于激活状态时,平台调用它的 run() 方法,下面的例子展示了jobs:

   class TrivialJob extends Job {
      public TrivialJob() {
         super("Trivial Job");
      }
      public IStatus run(IProgressMonitor monitor) {
         System.out.println("This is a job");
         return Status.OK_STATUS;
      }
   }

 

下面的代码中创建并调度了一个作业:

   TrivialJob job = new TrivialJob();
   System.out.println("About to schedule a job");
   job.schedule();
   System.out.println("Finished scheduling a job");

这个程序的输出和时间是无关的,也就是说,对于创建和调度job的线程来说,没有办法确定作业 的run 方法什么时候运行, 输出要么是:

   About to schedule a job

   This is a job

   Finished scheduling a job

或者:

   About to schedule a job

   Finished scheduling a job

   This is a job

如果你想确保在继续进行之前作业运行结束,可以使用 join() 方法,这个方法将会阻塞调用者线程,直到作业 结束,或者知道调用线程被中断。以一种更确定的方式重写上面的代码:

   TrivialJob job = new TrivialJob();
   System.out.println("About to schedule a job");
   job.schedule();
   job.join();
   if (job.getResult().isOk())
      System.out.println("Job completed with success");
   else
      System.out.println("Job did not complete successfully");

如果join() 调用没有被中断,这个方法会返回下面的结果:

   About to schedule a job

   This is a job

   Job completed with success

当然,在调度之后就join 作业通常没有什么用处,因为这样做不能实现并发。在这种情况下,不妨直接在调用线程中通过作业 的run 方法实现需要的工作,后面我们将会通过一些例子看看join 更具意义的用途。

 

        上面的代码也用到了作业 result 。result 是作业的run() 方法返回的IStatus 对象。你可以使用这个result 传递任何必要的来自作业的run 方法的对象。redult 也可以用来表示失败(返回一个带有严重 IStatus.ERROR 的IStatus),或者取消(IStatus.CANCEL)。

 

2. 通用作业操作

        我们已经看到是怎样运行一个作业并等待它结束的,使用job还可以做许多其他方面的事情,如果你运行了一个作业但决定不再使用,可用使用cancel() 方法停止作业。如果取消job时还没有开始运行,作业会立即被放弃并停止运行。另一方面,如果作业已经开始运行,作业将决定是否对取消操作作出反应。可以取消一个作业,同时join()可以用于阻塞调用线程。下面是取消作业的习惯方法:

if (!job.cancel())
      job.join();

如果取消操作没有立即起作用,那么cancel() 将会返回false,调用者将会是使用join() 方法等待作业被成功取消。

 

比取消操作宽松一些的方法是slee(),如果作业还没有开始运行,这个方法将会使作业完全暂停,平台仍然会记录作业,wakeUp() 可以让作业加入到等待队列中。

 

3. 作业状态

  • WAITING 表示作业将要运行,但是还没有开始运行
  • RUNNING 表示作业正在运行
  • SLEEPING 表示作业由于调用了sleep方法或者因为延迟执行而处于睡眠状态
  • NONE 表示作业不是处于waiting、running、sleeping 状态。当作业已经创建但是还没有被调度时作业处于NONE状态。也表示作业运行结束之后或已经被取消的状态

4. 作业监听器

        作业的方法addJobChangeListener 用于为一个特定的作业注册一个监听器,IJobChangeListener 定义了对job状态发生变化作出反应的方法:

  • aboutToRun   作业将要运行时触发
  • awake            睡眠状态中的作业进入等待运行状态时触发
  • done              作业完成执行时触发
  • running          作业开始运行时触发
  • scheduled      作业被调度并处于等待作业队列中是触发
  • sleeping         等待状态下的作业进入睡眠状态时触发

对于所有这些方法,监听器提供了一个IJobChangeEvent 参数, 表示作业正在进行的状态变化过程和或称完成时的状态。

 

5. 作业管理器(job manager)

        IJobManager 定义了系统中所有作业的工作方法,显示进度或使用job基础工具的插件可以使用IJobManager 来执行任务,例如挂起系统中所有的作业, 找出哪一个作业正在运行,或者接收一个特定作业的进度反馈,可以通过Platform API 获得平台作业:

IJobManager jobMan = Platform.getJobManager();

如果插件需要关注系统中所有作业的状态,可以为作业管理器注册一个作业变更监听器,而不是为每一个作业都注册一个监听器。

 

6. 作业家族

        有时候在插件中把一组相关的作业当作一个独立的单元可以起到简化的作用,使用作业家族(job families)可以实现这种方式,作业可以通过覆盖belongsTo 方法可以声明属于一个特定家族:

   public static final String MY_FAMILY = "myJobFamily";
   ...
   class FamilyJob extends Job {
      ...
      public boolean belongsTo(Object family) {
         return family == MY_FAMILY;
      }
   }

 

IJobManager 提供了能够取消、加入(join)、阻塞、或发现作业家族中的所有作业的方法:

   IJobManager jobMan = Platform.getJobManager();
   jobMan.cancel(MY_FAMILY);
   jobMan.join(MY_FAMILY, null);

        作业家族可以使用任意的对象来表示,你可以在作业家族中存储需要的状态,作业可以动态地按照需要创建作业家族对象,重要的是使用作业家族可以避免和其他插件所创建的作业家族产生意外交互,这种情况肯比较少见。

 

         作业家族也是方便查询作业组的方法,IJobManager.find(Object family)  可以在任何给定时间发现正在运行、等待和阻塞的作业实例。

 

7. 在关闭之前完成作业

        因为作业可以并行运行,在平台开始关闭时,作业可能还在运行,这是一个很危险的情况,应为插件停止之后,作业可能无法正确工作或者不能家族所需类。由于这个原因,确保在插件的停止方法中去需或结束所有作业时非常重要的。像上面的例子一样,你可以使用作业家族,来确保在插件停止运行之前所有在插件中调度的作业已经被取消或者joined。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics