栏目导航
热点推荐
- 三十条有用的 Java 编程规则
- Java制作水印图片源码
- Java常见异常及可能的导致原因
- Java中的修饰词使用方法总结
- J2EE系统异常的处理准则
- Java中的异常、断言、日志解析(
- Java面试技巧:Java面试题集锦(
- 面向Java开发人员的Scala指南:
- Java程序员:一刻钟精通正则表达
- 网友经验分享:学好java开发的关
- 专家解答:创建表格与数据库进行
- Java远程访问Domino数据库
阅览排行
实时Java开发(1): 探索实时Java的独特功能
www.jz123.cn 2009-10-20 来源: IT专家网 责任编辑(袁袁) 我要投递新闻
实时 Java 是对 Java 语言的一组增强,为应用程序提供了一定程度的实时性能,这些实时性能是标准 Java 技术所不能提供的。传统的吞吐量性能通常是对可在固定时间量内完成的指令、任务或工作的总数的衡量。与传统的吞吐量性能不同,实时性能专注于应用程序(在不超出给定时间约束的情况下)响应外部刺激因素所需的时间。在硬 实时系统中,决不能超出这类约束;软 实时系统对违规具有更高的容忍度。实时性能要求应用程序本身控制处理器,以便它能够响应刺激因素,并且在响应刺激因素的同时,虚拟机内的竞争进程不会阻止应用程序代码的执行。实时 Java 在 Java 应用程序中交付了前所未有的响应能力。
实时 JVM 可利用实时操作系统(real-time operating system,RTOS)服务来提供硬实时功能,或者可以为具有比较软的实时约束的应用程序运行一个或多个传统操作系统。在使用实时 JVM 时,可以免费使用实时 Java 中使用的一些技术。但是为了探索实时 Java 中的一些特性,需要对应用程序进行一些更改。这些特性是本文介绍的重点。
必须约束的子进程
JVM 服务是一个执行工作的给定应用程序,这些工作仅能被该应用程序松散地控制。一些运行时子进程在 JVM 内部运行,包括:
垃圾收集:此任务用于收回应用程序不再使用的运行时内存块。垃圾收集可以使应用程序执行延迟一段时间。
类加载:此进程(之所以称为类加载,是因为 Java 应用程序是在类粒度级别加载的)涉及从文件系统或网络加载应用程序结构、指令和其他资源。在标准 Java 中,应用程序在第一次引用一个类时加载这个类(延迟 加载)。
即时(Just-in-time,JIT)动态编译:许多虚拟机在应用程序运行时通过动态编译将方法由 Java 字节码解释为本地机器指令。尽管这可以提高性能,但编译活动本身可能导致临时延迟,阻止应用程序代码运行。
调度:在标准 Java 中,应用程序只有极小的控制权限来调度自己的运行线程,以及调度与在同一操作系统上运行的其他应用程序相关的应用程序。
所有这些子进程都可能限制应用程序响应外部刺激因素的能力,因为它们可能延迟应用程序代码的执行。例如,可以调度一个指令序列来响应来自网络、雷达系统、键盘或任何其他设备的信号。实时应用程序具有一段很短的可接受时期,在此期间,允许不相关的进程(比如垃圾收集)延迟响应指令序列的执行。
实时 Java 提供了各种技术,旨在最小化底层子进程对应用程序的干扰。切换到实时 JVM 时可使用的 “免费” 技术包括:限制了收集操作的持续时间和干扰影响的专门垃圾收集,允许在启动时优化性能(而不是延迟优化)的专门的类加载,专门的锁定和同步,以及能够避免优先级反转的专门的优先线程调度。但是,可能需要对应用程序进行一些修改,要利用 Java 实时规范(Real-Time Specification for Java,RTSJ)引入的特性时更应如此。
RTSJ 提供了一个支持 JVM 中大量实时特性的 API。一些特性在规范实现中是强制性的,另一些是可选的。规范包括以下一般区域:
实时调度
高级内存管理
高精度计时器
异步事件处理
异步线程中断
Realtime 线程
RTSJ 定义了 javax.realtime.RealtimeThread — 标准 java.lang.Thread 类的一个子类。从本质上讲,RealtimeThread 支持规范中的一些高级特性。例如,实时线程受实时线程调度器控制。该调度器提供了一个独特的调度优先级范围,可以实现先入先出的实时调度策略(确保最高优先级的线程不会受到干扰),以及优先级继承(该算法可阻止较低优先级线程无限期地持有需要不受干扰地运行的较高优先级线程所需的锁,这种情形称为优先级反转)。
可以在代码中明确构造 RealtimeThread 的实例。但是也可以轻松更改应用程序来启用实时线程,从而避免繁重的开发工作和相关成本。这里给出了干扰最小且最透明地启用实时线程的各种方式的示例。(可以 下载 本文所有示例的源代码)。这些技术使应用程序能够最轻松地利用实时线程,使应用程序能够保持与标准虚拟机兼容。
按优先级分配线程类型
清单 1 给出了一段代码,这段代码根据优先级值分配一个实时或常规线程。如果在实时虚拟机上运行,一些线程可能是实时线程。
清单 1. 根据优先级分配线程类型
import javax.realtime.PriorityScheduler; import javax.realtime.RealtimeThread; import javax.realtime.Scheduler; public class ThreadLogic implements Runnable { static void startThread(int priority) { Thread thread = ThreadAssigner.assignThread( priority, new ThreadLogic()); thread.start(); } public void run() { System.out.println("Running " + Thread.currentThread()); } } class ThreadAssigner { static Thread assignThread(int priority, Runnable runnable) { Thread thread = null; if(priority <= Thread.MAX_PRIORITY) { thread = new Thread(runnable); } else { try { thread = RTThreadAssigner.assignRTThread(priority, runnable); } catch(LinkageError e) {} if(thread == null) { priority = Thread.MAX_PRIORITY; thread = new Thread(runnable); } } thread.setPriority(priority); return thread; } } class RTThreadAssigner { static Thread assignRTThread(int priority, Runnable runnable) { Scheduler defScheduler = Scheduler.getDefaultScheduler(); PriorityScheduler scheduler = (PriorityScheduler) defScheduler; if(priority >= scheduler.getMinPriority()) { return new RealtimeThread( null, null, null, null, null, runnable); } return null; } } |
清单 1 中的代码必须与 RTSJ 类一起编译。在运行时,如果未找到实时类,代码将捕获虚拟机抛出的 LinkageError 并实例化常规 Java 线程来代替实时线程。这允许代码在任何虚拟机(无论是否实时虚拟机)上运行。
在清单 1 中,提供 RealtimeThread 对象的方法被指定为自身的一个类。通过这种方式,只有在加载该类时才会验证该方法,这在第一次访问 assignRTThread 方法时完成。当加载类时,运行时虚拟机字节码验证器尝试验证 RealtimeThread 类是否为 Thread 类的子类,如果为找到实时类,验证将失败并抛出 NoClassDefFoundError。
使用反射分配线程
清单 2 演示了一种替代技术,它具有的效果与清单 1 相同。它首先设置一个优先级值来确定期望的线程类型,根据类名称实例化实时线程或常规线程。这段反射式代码要求类中存在一个构造函数,这个函数接受一个 java.lang.Runnable 实例作为最后的参数,为所有其他参数传递空值。
清单 2. 使用反射来分配线程
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class ThreadLogic implements Runnable { static void startThread(int priority) { Thread thread = ThreadAssigner.assignThread( priority, new ThreadLogic()); thread.start(); } public void run() { System.out.println("Running " + Thread.currentThread()); } } class ThreadAssigner { static Thread assignThread(int priority, Runnable runnable) { Thread thread = null; try { thread = assignThread(priority <= Thread.MAX_PRIORITY, runnable); } catch(InvocationTargetException e) { } catch(IllegalAccessException e) { } catch(InstantiationException e) { } catch(ClassNotFoundException e) { } if(thread == null) { thread = new Thread(runnable); priority = Math.min(priority, Thread.MAX_PRIORITY); } thread.setPriority(priority); return thread; } static Thread assignThread(boolean regular, Runnable runnable) throws InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException { Thread thread = assignThread( regular ? "java.lang.Thread" : "javax.realtime.RealtimeThread", runnable); return thread; } static Thread assignThread(String className, Runnable runnable) throws InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException { Class clazz = Class.forName(className); Constructor selectedConstructor = null; Constructor constructors[] = clazz.getConstructors(); top: for(Constructor constructor : constructors) { Class parameterTypes[] = constructor.getParameterTypes(); int parameterTypesLength = parameterTypes.length; if(parameterTypesLength == 0) { continue; } Class lastParameter = parameterTypes[parameterTypesLength - 1]; if(lastParameter.equals(Runnable.class)) { for(Class parameter : parameterTypes) { if(parameter.isPrimitive()) { continue top; } } if(selectedConstructor == null || selectedConstructor.getParameterTypes().length > parameterTypesLength) { selectedConstructor = constructor; } } } if(selectedConstructor == null) { throw new InstantiationException( "no compatible constructor"); } Class parameterTypes[] = selectedConstructor.getParameterTypes(); int parameterTypesLength = parameterTypes.length; Object arguments[] = new Object[parameterTypesLength]; arguments[parameterTypesLength - 1] = runnable; return (Thread) selectedConstructor.newInstance(arguments); } } |
清单 2 中的代码无需与类路径上的实时类一起编译,因为实时线程使用 Java 反射来实例化。
上一篇:Java基础:Util包下常用的数据结构介绍 下一篇:Java 设计模式之 观察者模式(Observer)