KVM具有独立于机器的、可移植的线程模型,可以独立于Java语言运行.
其变化如下:
1.0之前
使用了一个简单的循环调度模型,其中系统中的所有活动线程都存储在循环列表中.
列表中的线程根据每个任务的Java级优先级,一个接一个地执行。在实现级别,线程优先级只是一个整数,它告诉解释器在下一个线程切换发生之前,线程可以执行多少原语。在每个字节码执行之后,线程的“Timeslice”计数器将递减。当时间片变为零时,将强制执行线程切换。一些I/O原语也可以启动线程切换。
1.0
加入了异步(非阻塞)I/O。
另一个目标是引入轻松实现替代调度机制的能力,但不太彻底地改变现有系统。
在最初的系统环境中,许多地方发生了切换。现在,它只在解释器调度循环的顶部完成。在原始版本中,可运行的线程与当前正在执行的线程一起保存在循环列表中。现在,当线程开始执行时,每个线程都会从可运行线程的循环列表中删除,当线程被阻塞时,会返回到循环列表中。
变量up已重命名为当前线程,并指向当前正在执行的线程。一个新的变量runnable threads指向可运行线程的循环列表。
suspendThread() 方法有所改变.
它以前有一个要挂起哪个线程的参数,但在任何情况下都不能挂起,所以该参数已被删除。这个例程用于执行上下文切换,但现在它只将currentThread置零,并调用一个名为signalTimeToReschedule()的新函数,该函数向解释器发出信号,表示在执行下一个字节码之前应该重新调度VM。
为解释器提供了一个新的函数istimeToReschedule()来测试这种情况,并调用了一个新的函数reschedule()来测试这种情况。解释器字节码调度循环顶部的代码现在是:
if (isTimeToReshedule()) {
reschedule();
}
isTimeToReshedule() 为宏,宏展开后为: Timeslice-- == 0.signalTimeToReschedule()也会宏,其只是将Timeslice 设置为0.
并定义了如下方法:
-
startThread()
标记线程存活,但是是暂停状态
-
resumeThread()
此函数将线程放回可运行线程列表(runnablethreads),如果激活的线程的优先级高于当前执行的线程的优先级,也将调用signalTimeToReschedule()。
-
BuildThread()
现在,这会将所有新线程添加到另一个名为all threads的活动线程列表中。此列表由垃圾收集器使用。
-
DismantleThread()
从AllThreads 中移除
-
stopThread()
此函数与buildThread()的逻辑相反。它挂起线程并调用Dismantlethread()。
-
resumeThread()
这将替换使用ActivateThread()重新启动挂起的线程。
-
isActivated()
在调用这个例程之前,必须测试currentThread是否为非空
-
HandleEvent()
因为原始handleEvent例程调用了ActivateThread,所以它不需要任何更改(isActivated()的调用约定除外)。 但是,返回参数的含义现在略有不同,这意味着向runnablethreads添加了一个新线程,而不是它只是切换了上下文。
-
SwitchThread()
switchthread现在只从reschedule()调用。当前线程可以指向线程,也可以不指向线程。如果这样,我们会像以前一样通过runnablethreads列表旋转线程。如果它为空并且runnablethreads列表为空,则函数返回false,并且reschedule()必须决定要做什么。
-
JLT_Yield()
只在signalTimeToReschedule()中调用
此外,还支持了异步i/0.
1.0.3
kvm 1.0.3有一个新的monitor/synchronization实现。
线程模型
在kvm中内部,为每个线程实例化以下结构之一:
- THREAD : 是一种内部(VM级)结构,用于存储独立于Java级的东西来实现抢占任务切换的必要信息。活动线程单独链接到包含系统中所有活动线程的线性列表。
- JAVATHREAD: JAVATHREAD被映射到Java类“Thread.java”中定义的实例结构。它是从线程引用的。
为什么定义这两个结构? 其原因是为了便于移植,kvm希望保持线程系统实现与Java语言无关。
其中THREAD定义如下:
struct threadQueue {
THREAD nextAliveThread; /* alive线程队列 */
THREAD nextThread; /* 运行或等待线程队列 */
JAVATHREAD javaThread; /* 包含java 级别的线程信息 */
long timeslice; /* 从Java级线程优先级计算而来*/
STACK stack; /* 该线程的执行栈*/
/*
* 以下四个变量用于在线程可运行时存储线程的虚拟机寄存器(=active,但不是当前给定的处理器时间)。
* 为了方便垃圾收集,我们将指向执行堆栈的指针存储为偏移量,而不是实际指针。
* */
BYTE* ipStore; /* 程序计数器*/
FRAME fpStore; /* 帧*/
cell* spStore; /* sp*/
cell* nativeLp; /* 在KNI的调用中用来访问本地变量*/
MONITOR monitor; /* 当前线程的monitor*/
short monitor_depth;
THREAD nextAlarmThread; /* 在当前队列中的下一个线程 */
long wakeupTime[2]; /* 我们不能要求堆对象的8字节对齐 */
void (*wakeupCall)(THREAD); /* 线程唤醒时调用 */
struct {
int depth;
long hashCode;
} extendedLock; /* 在FASTLOCK时使用*/
char* pendingException; /* 线程将要抛出异常的类名 */
char* exceptionMessage; /* 要抛出异常的信息 */
enum {
THREAD_JUST_BORN = 1, /* 还没有启动 */
THREAD_ACTIVE = 2, /* 当前正在运行,或者在等待运行的队列中 */
THREAD_SUSPENDED = 4, /* 等待monitor或者alarm */
THREAD_DEAD = 8, /* 线程退出 */
THREAD_MONITOR_WAIT = 16,
THREAD_CONVAR_WAIT = 32,
THREAD_DBG_SUSPENDED = 64
} state; // 线程状态定义
bool_t isPendingInterrupt; /* Don't perform next sleep or wait */
#if ENABLE_JAVA_DEBUGGER
bool_t isStepping;
bool_t isAtBreakpoint;
bool_t needEvent;
CEModPtr debugEvent;
ByteCode nextOpcode;
struct singleStep_mod stepInfo;
int debugSuspendCount;
#endif /* ENABLE_JAVA_DEBUGGER */
};
JAVATHREAD定义如下:
struct javaThreadStruct { /* (A true Java object instance) */
COMMON_OBJECT_INFO(INSTANCE_CLASS)
long priority; /* 线程的优先级*/
THREAD VMthread; /* 执行vm thread */
INSTANCE target; /* 执行run的对象 */
SHORTARRAY name; /* 线程名称*/
};