来调度将执行的代码,以响应异步或定期事件。(如果事件是由定时器发起的,那么它们可能是定期的)。这使您无需为这类事件显式地调度线程。相反。虚拟机维护一个共享线程池,该线程池被分派用于在发生事件时运行异步事件处理器的代码。这可以简化实时应用程序,将您从对线程和内存区域的管理中解放出来。
图 2 中的类图显示了可用于调度代码的选项:
图 2. 此类图演示了调度代码的选项
图 3 展示了如何分派异步事件处理其:
图 3. 异步事件处理器分派方式
使用实时Java进行开发,第1部分 探索实时Java的独特功能(7)
时间:2011-01-27 IBM Sean C. Foley
一般而言,可移植性和模块化有助于将响应事件的代码与启用和分派处理器的代码分离开来。当将代码封装到 java.lang.Runnable 实现中之后,可以通过许多选项来分派该代码。可以选择构造一个线程来执行代码,或者使用异步事件处理器(利用线程池)按需执行代码,或者将两者结合使用。
表 1 比较了各种可能选择的特征:
表 1. 对比在实时 Java 中分派代码的各种方法
|
共享执行代码的线程 |
可定期分派 |
可在堆内存中运行 |
可在永远空闲内存中运行 |
可在范围内存中运行 |
可为其分配一个期限 |
将在不受垃圾收集干扰的情况下运行 |
常规 Thread |
否 |
否 |
是 |
是 |
否 |
否 |
否 |
RealtimeThread |
否 |
是 |
是 |
是 |
是 |
是 |
否 |
NoHeapRealtimeThread |
否 |
是 |
否 |
是 |
是 |
是 |
是 |
AsyncEventHandler |
是 |
是,当附加到周期计时器时 |
是 |
是 |
是 |
是 |
否 |
BoundAsyncEventHandler |
否 |
是,当附加到周期计时器时 |
是 |
是 |
是 |
是 |
否 |
无堆 AsyncEventHandler |
是 |
是,当附加到周期计时器时 |
否 |
是 |
是 |
是 |
是 |
无堆 BoundAsyncEventHandler |
否 |
是,当附加到周期计时器时 |
否 |
是 |
是 |
是 |
是 |
当考虑使用哪些调度选项和内存区域时,会遇到实时 Java 独有的一些设计问题。一般而言,为实时环境编程比编写直观的传统应用程序更具挑战性,并且实时 Java 自身也具有一些挑战性。表 2 列出了当使用附加内存区域、NHRT 和其他实时特性时可能带来的一些复杂性:
表 2. 实时线程和内存区域的一些复杂性和难题
考虑因素 |
细节 |
分配给内存区域的内存 |
应用程序创建的每个内存区域会被分配所申请的内存大小。选择的大小太大会降低内存使用效率,但是选择的大小太小很容易使应用程序遇到 OutOfMemoryError。在开发期间,即使应用程序没有变化,底层库也可能改变。这可能导致意外的附加内存使用,导致内存使用超出内存区域限制。 |
共享范围的计时因素 |
多个线程共享的范围内存区域的无需很大,因为在没有内存使用它时会将它清除。但是,对使用范围的线程计时稍作更改之后,范围就会始终被用作线程的分配上下文。这将导致该范围始终不会被清除,导致 OutOfMemoryError。
当进入和清除共享的范围区域时,线程之间可能发生临时的锁争用。 |
运行时异常 IllegalAssignmentError、MemoryAccessError 和 IllegalThreadStateException |
如果未足够重视代码设计,就可能发生这些异常。实际上,对程序行为和计时的细微更改可能导致这些异常的意外出现。一些示例包括:
由于线程之间的计时和同步变化,堆中在正常情况下不可被 NHRT 使用的对象可能变得可用。
当不知道从哪个内存区域分配对象或者特定范围位于范围堆栈上的何处时,可能发生 IllegalAssignmentError。
当进入范围内存区域的代码由常规线程运行时,将抛出 IllegalThreadStateException。
由于分配规则的限制,通常使用静态字段或其他缓存数据方式的代码会使范围不安全,可能导致 IllegalAssignmentError。 |
类初始化 |
任何类型的常规或实时线程都可以初始化类,包括 NHRT(它可能导致意外的 MemoryAccessError)。 |
使用 finalize 方法终结对象 |
退出范围的最后一个线程用于终结范围中的所有对象:
如果 finalize 方法创建线程,则范围可能不能如期被清除。
终结也可能导致死锁。在终结内存区域之前,终结线程可能获取了锁。其他线程可能会争用这些锁和在终结期间将获取的锁,进而导致死锁。 |
意外 NHRT 延迟 |
尽管可以保证 NHRT 的运行不会受到垃圾收集的直接干扰,但 NHRT 可能与由垃圾收集抢占的其他线程类型共享相同的锁。如果 NHRT 在尝试获取这类锁时被延迟了,而且拥有该锁的线程被垃圾收集延迟了,那么垃圾收集也会间接地延迟 NHRT。 |
|