技术开发 频道

实时Java,线程化和同步

        本节将介绍 RT 同步的一些特性,这些特性可以帮助移植应用程序的开发人员使用 RT 线程或编写新的应用程序以使用 RT 线程化。

  普通 Java 线程和 RT 线程之间的锁争用

  RT 线程可能被普通 Java 线程持有的锁阻塞。发生这种情况时,优先级继承接管线程,因此普通 Java 线程的优先级被提高到 RT 线程的优先级,并且只要它持有锁就一直保持该优先级。普通 Java 线程继承了 RT 线程的所有调度特征:

  普通 Java 线程按 SCHED_FIFO 策略运行,因此线程不划分时间片。

  在提高了优先级的 RT 运行队列中进行调度和让步。

  此行为在普通 Java 线程释放锁时返回到 SCHED_OTHER。如果 清单 1 中创建的两个线程在持有 RT 线程所需要的锁的时候都不运行,则该程序将不会结束并且出现我们在 使用 RT 线程的问题代码示例 部分中描述的问题。因为可能出现这种情形,所以对于所有在实时 JVM 中执行的线程来说,执行 spin 循环和让步并不明智。

  NHRT 和 RT 线程之间的锁争用

  NHRT 可能在 RT 线程(或相应的普通 Java 线程)持有的锁处阻塞。虽然 RT 线程持有锁,但是 GC 可能抢占 RT 并间接地抢占 NHRT。NHRT 需要一直等到 RT 不再被 GC 抢占并释放锁后才能执行。如果 NHRT 执行的功能具有严格的时间要求,则 GC 抢占 NHRT 将是一个严重的问题。

  WebSphere Real Time 中具有确定性的垃圾收集器将暂停时间保持在一毫秒以下,使 NHRT 抢占更具有确定性。如果不能容忍此类暂停,则可以通过避免 NHRT 和 RT 线程之间的锁共享来绕过该问题。如果强制使用锁定,则可以考虑使用特定于 RT 或 NHRT 的资源和锁。例如,实现线程入池的应用程序可以考虑对 NHRT 和 RT 线程使用分开的池和池锁。

  同样,javax.realtime 包提供了以下的类:

  WaitFreeReadQueue 类主要用于将对象从 RT 线程传递到 NHRT。

  WaitFreeWriteQueue 类主要用于将对象从 NHRT 传递到 RT 线程。

  RT 线程在执行无等待操作时可能被 GC 阻塞,上述类保证了 RT 线程在执行无等待操作时不会持有 NHRT 所需的锁。

  javax.realtime 包中的同步

  某些 javax.realtime 方法故意没有实现同步,因为即使锁是无争用的,同步也会造成系统开销。如果需要同步,则调用方负责封装同步方法或块中所需的 javax.realtime 方法。编程人员在使用 java.realtime 包的方法时必须考虑添加此类同步。

  核心 JLS 包中的同步

  相反,如 java.util.Vector 之类的核心 JLS 服务已经实现同步。同样,某些核心 JLS 服务可以执行一些内部锁定来序列化某些共享资源。由于这种同步,在使用核心 JLS 服务时,必须谨慎执行以避免 GC 抢占 NHRT 的问题。

  无争用锁定的性能

  非 RT 应用程序的标准检查和检测已表明锁定主要是无争用的。无争用锁定同样被认为是 RT 应用程序中的主要类型,特别是现有组件或库需要重用的时候。如果已知锁定是无争用的但是难以避免或删除同步指令,则对这些锁定花费一点小的确定的开销不失为明智的做法。

  如前所述,无争用锁定操作涉及了一些设置和一个原子机器指令。解锁操作涉及一个原子机器指令。锁定操作的设置涉及分配一个预先锁定的互斥锁。该分配被认为是无争用锁定操作中最大的可变开销。RealtimeSystem.setMaximumConcurrentLocks() 可以帮助控制这种可变开销。

  RealtimeSystem.setMaximumConcurrentLocks(int numLocks) 使 WebSphere Real Time 中的 VM 将 numLocks 互斥锁预先分配给全局锁缓存。全局锁缓存将其内容提供给单线程锁缓存。通过使用这个 RealTimeSystem API,可以降低具有严格时间要求的代码区域中发生锁定初始化的机率。RealTimeSystem.getMaximumConcurrentLocks() 可以用来帮助决定 setMaximumConcurentLocks() 调用中应该使用的数量,但是要注意 getMaximumConcurrentLocks() 提供关于调用的锁使用,而不是最高使用标记(high-water mark)。未来的 RTSJ 版本可能提供 API 以便提供最高使用标记。不要为 numLocks 的值提供很大的值,因为调用 setMaximimConcurrentLocks() 可能耗费过量的时间和内存来创建那些锁。还要注意:这个 API 是定义为 JVM 专用的,因此其他 JVM 可能忽略该调用或提供不同的行为。

  争用锁定的性能

  一个线程可以同时持有多个锁,并且可能已经按某种顺序获得了这些锁。所有此类锁定模式形成了一个锁层次结构。优先级继承可以指提高和降低一组线程的优先级。组中线程的数量应该不大于系统中最深的锁层次结构的深度。通过保持较浅的锁层次结构,可以锁定最少量的对象,您能够影响最大量的需要调整优先级的线程。

  同步操作中的时间

  Object.wait(long timeout, int nanos) 为相关的等待操作提供纳秒粒度。HighResolutionTime.waitForObject() API 与 Object.wait() 类似并提供可使用纳秒粒度指定的相对时间和绝对时间。在 WebSphere Real Time 中,这两个 API 都使用底层 POSIX 锁定等待服务来实现。这些底层服务最多提供微秒粒度。如有需要,出于可移植性目的,javax.realtime 包的 Clock 类的 getResolution() 方法应用于检索执行平台的分辨率。

  结束语

  RTSJ 通过 javax.realtime 包中的新 RT 类和 API 扩展并加强了 Java 编程人员的线程化和同步功能。在 WebSphere Real Time 中,这些功能通过 Linux 内核的 RT 版本来实现,对 POSIX 线程化进行修改并对 JVM 自身进行修改。您现在对 RTSJ 线程化和同步有了更深入的了解,这些知识可以帮助您在编写和部署 RT 应用程序时避免问题的发生。

0
相关文章