java线程管理

java线程管理

参见: http://harmony.apache.org/subcomponents/drlvm/TM.html

1. 修订历史

2. 关于本文档

3. 概览

4. 体系结构

5. 使用场景

6. 参考文献

1. 修订历史


版本


版本信息


日期


初版


Nadya Morozova, Andrey Chernyshev: 创建文档.


2006年6月5日

2. 关于本文档

2.1. 目的

本文介绍了线程管理器组件,该组件是作为动态运行时层(Dynamic Runtime Layer, DRL)计划的一部分递交的。本文主要关注DRL虚拟机中线程管理器任务的当前实现细节,以及线程管理子系统的内部组织结构。

2.2. 面向的读者

本文面向的读者包括对线程技术的进一步工作感兴趣,并且愿意贡献其开发的广大的工程师群体。本文假设读者对于DRLVM体系结构基础、线程方法学和结构都相当熟悉。

2.3. 文档约定

本文使用对DRL文档包的统一约定。

2.4. 文档使用

本文可以用来学习所有当前版本的实现细节。本文从多个方面描述线程管理器的功能,包括内部数据结构、体系结构细节以及线程管理器关键的使用场景。本文有如下主要部分:

  • 概览:给线程管理器组件及其在VM体系结构中的地位做了一个概括的定义。
  • 体系结构:描述了线程管理器的内部结构、数据结构和开放的接口。
  • 使用场景:展示了主要的线程相关操作,例如线程生命周期和线程挂起。
  • 参考文献:连接到与本文内容有关的材料。

3. 概览

线程管理器(TM)是一个致力于为Java*虚拟机提供线程支持的库,它的目标是在操作系统提供的类POSIX线程模型和由J2SE规范建立的类Java*线程模型之间架设一座桥梁。

在当前的实现中,JVM线程子系统包括以下三层:

  • 与操作系统交互的移植层(porting layer)
  • 提供基本线程功能的本地层(native layer)
  • 与用户应用程序的Java*对象交互的Java*层(Java* layer)

需要注意的是:线程管理器包含该子系统的native layer和Java* layer;而porting layer在线程管理器外部。

每一层都为下层提供的线程支持增加某些功能。就是说,porting layer为操作系统提供的线程支持添加了可移植性(portability);native layer为porting layer提供的线程支持添加了Java*特定的增强;而Java* layer将Java*线程和对象连接到native layer,如图 1所示。这些接口被组织在一个头文件集合中,在下面的对外接口一节中描述。



图 1. 线程子系统

3.1. 主要特点

提供的线程管理器有如下特点:

  • 支持J2SE API1]、JVMTI2]和JNI3]规范要求的线程功能
  • 基于Apache Porting Layer的可移植实现4]
  • 遵从Harmony hythread 接口8]
  • 支持垃圾收集器
  • 特定于DRLVM提供的即时编译器(just-in-time, JIT)的监视器(monitor)优化

3.2. VM中的线程管理器

图 2 展示了线程管理器与以下的虚拟机组件之间的交互:

  • 虚拟机核心(VM core):通过它来访问对象的布局信息,从而将java.lang.Thread对象与适当的本地线程进行绑定。为此,线程管理器要查询虚拟机核心的thread_externals.h接口。
  • 垃圾收集器(garbage collector):通过它来满足垃圾收集器的根集枚举和垃圾收集活动的线程操作需求。GC和线程管理器的native layer一起工作。
  • 移植层(porting layer):通过它来与底层系统进行交互,保证线程支持的可移植性。线程管理器的native layer需要查询APR接口和apr_thread_ext接口的方法。
  • 即时编译器(just-in-time compiler):通过它来为JIT编译后的代码提供优化的线程支持功能,这些功能会被VM 帮助器调用。线程管理器通过Java* layer的thread_helpers接口开放这些功能。


图 2. VM体系结构中的线程管理器

3.3. 可移植性

线程管理器的代码大部分是平台无关的,依靠底层的porting layer适应特定的平台。当前的TM实现在Apache Porting Layer(APR)之上通过添加额外的扩展完成。平台相关的TM部分包括绑定到特定体系结构上的VM 帮助器包和部分绑定到OS API上的APR扩展包。

基于APR的移植使得线程管理器代码可以在任何APR可用的平台上进行编译。线程管理器的当前版本支持Linux*和Windows* IA-32平台。

4. 体系结构

下面几节描述了线程管理器与其它VM组件交互时开放的功能接口及其内部数据结构。

4.1. 对外接口

如概览所述,线程管理器对外提供native和Java*接口。这些接口表现为一组为外部请求提供特定功能的函数,在后面的节中描述。

4.1.1. Native接口

Native接口由Harmony hythread模块得到启发。这是一个低级的提供类Java*线程功能的层,例如对等待操作(waitparkjoinsleep等)的中断支持。该接口帮助建立了线程与垃圾收集器间正确的交互。它并不处理Java*对象。

Native接口包含下列函数集:

hythread.h



hythread集合的函数8],其作用包括:

  • 基本操作
  • 暂停(Parking)
  • 线程本地存储支持
  • 读写互斥量支持
  • 监视器支持

hythread_ext.h



扩展hythread集合的一组函数,其作用包括:

  • 线程管理器的初始化和关闭
  • 线程组支持
  • 条件变量
  • 安全挂起支持
  • 闭锁(Latch )
  • 线程迭代器支持
  • 属性访问(Attributes access)
  • 线程的查询状态(Querying state of the thread )
  • 信号量
  • 互斥量
  • 瘦(thin)监视器支持
  • 查询线程状态 (Querying the thread state)
  • 线程属性访问(Thread attributes access)
  • 中断支持
  • 任务管理支持

4.1.2. Java* 接口

Java*接口将native layer提供的线程支持功能连接到Java*线程和对象。

Java*的接口函数把Java*对象作为参数,可以容易地用来实现内核类(kernel classes)、JNI或者JVMTI函数集合。Java*接口包括三部分:

jthread.h



支持java.lang.Objectjava.lang.Thread API的函数,其作用包括:

  • 基本操作
  • 标识
  • 指针变换
  • 属性访问
  • 中断
  • 监视器
  • Parking
  • 挂起

ti_thread.h



支持不同JVMTI函数和java.lang.management API的函数,其作用包括:

  • 状态查询
  • 插桩
  • 本地存储
  • 监视器信息
  • CPU计时
  • 峰值(Peak)计数
  • 原始(Raw)监视器

thread_helpers.h



提供存根(stub)的函数。这些存根用于优化因线程管理器和JIT紧密地集成而带来的性能问题。

4.2. 数据结构

线程管理器的数据结构一般是不暴露的,外部的VM组件只能通过透明指针访问这些数据结构。这些指针被定义在头文件hythread.h、hythread_ext.h、jthread.h 和 ti_thread.h中。数据结构本身在thread_private.h中描述。

4.3. 线程控制结构

线程管理器要求每个线程在调用线程支持函数前要先被注册(registered)。线程注册被称为系附一个线程(attaching a thread),这可用如下函数实现:

  • hythread_attach()函数在线程管理器中注册当前线程,从而线程支持操作可以借助native layer在此线程上执行。
  • jthread_attach()函数在当前线程和适当的java.lang.Thread对象间建立联系,从而线程支持操作可借助Java* layer在此线程上执行。

依赖于系附函数(attaching function),线程管理器操作两种类型的线程:

  • Native thread:被系附到线程管理器的native layer上的本地(native)线程。
  • Java* thread: 被系附到线程管理器Java* layer上,且与一个java.lang.Thread对象相关联的Java*线程。

每个线程类型有相关的结构,这个结构保存了线程特定的数据,在后面有所讲述。 其它VM组件使用操作那些结构的不透明句柄进行工作,而不能获得它们的内容信息。以这种方式与线程工作的时候,组件调用系附函数中的一个,获得该线程的线程控制结构的不透明句柄,然后就可以使用这个句柄对这个线城进行任何操作了。

4.3.1. Native 线程结构

当对线程管理器的native layer注册的时候,每个线程获得一个控制结构,这个结构包含所有执行线程操作所需的线程特定数据,例如:状态、属性、对特定OS线程结构的引用以及同步辅助等。这个控制结构随后为各种线程支持操作所使用。

  • 注意: 线程控制结构的实际内容是与实现相关的,不暴露给其它组件。

下图展示了一个被HyThread类型描述的native系附线程的线程控制结构:



图 3. Native线程

下表列出了组成native线程的线程控制结构的数据域:


数据域


描述


挂起(Suspension)


IDATA


suspend_request


导致本线程挂起请求的数量。


int16


suspend_disable_count


指示线程可以被安全挂起的标志。


hylatch_t


safe_region_event


当一个线程进入安全区时用来通知相关线程的事件。


hysem_t


resume_event


用来通知一个挂起线程需要唤醒的事件。


hythread_event_callback_proc


safepoint_callback


当恢复一个线程时在安全点上执行的函数。


基本操作域(Basic manipulation fields)


hythread_group_t


group


本线程所在的组等同于该组的线程列表的表头地址。线程组被用来快速地在线程列表上迭代。例如:Java*线程、GC私有线程。


hythread_t


next


指向线程组中下一个线程。


hythread_t


prev


指向线程组中上一个线程。


apr_thread_t *


os_handle


OS线程的句柄。


void *


private_data


任何本线程相关数据的占位符。Java* layer使用该域存储与Java有关的上下文信息。


Boolean


exit_request


指示是否已经收到一个退出请求的标志。


IDATA


exit_value


本线程的退出值。


同步支持(Synchronization support )


hysem_t


park_event


暂停(Parking)线程事件。


hysem_t


sleep_event


Sleeping线程事件。


hylatch_t


join_event


为调用join的线程保留的事件。


hycond_t


current_condition


当前这个线程等待的条件变量。用作中断。


状态(State)


IDATA


state


线程状态。持有JVMTI规范中定义的线程状态标志加上附加标志。


属性(Attributes)


char *


name


线程名,用作调试。


IDATA


priority


为调度器提供线程优先级信息。


IDATA


daemon


检查该线程是否为守护进程。


其它(Others)


IDATA


thread_id


该线程的ID。线程的最大数目由锁字记录(lock word record)的大小决定。欲了解锁字记录结构的细节,请参见监视器结构一节。


apr_pool_t *


pool


内存池,线程被分配在其中。


apr_threadattr_t *


apr_attrs


APR线程属性。


hythread_entrypoint_t


start_proc


描述了会被执行的线程体的过程。


void *


start_proc_args


被传递到线程体的参数。


void *


thread_local_storage


代表线程本地存储的数组。


void *


big_local_storage


对标准本地存储槽的扩展。

线程控制结构的细节参见源代码包中的thread_private.h头文件。

4.3.2. Java* 线程结构

Java*线程的线程控制结构由JVMTIThread类型定义。它持有特定于那个线程的大部分JVMTI信息,如图 4所示。



图 4. Java* 系附的线程

下表列出了组成Java*线程的线程控制结构的数据域:


数据域


描述


JNIEnv *


jenv


与该Java*线程关联的JNI环境变量。


jthread


thread_object


与hythread_t关联的jthread对象。


hycond_t


monitor_condition


用来wait/notify Java*监视器的条件变量。


jthrowable


stop_exception


被一个停止线程抛出的异常。


jlong


blocked_time


该线程在一个监视器上阻塞的时间,单位纳秒。


jlong


waited_time


该线程等待一个监视器的时间,单位纳秒。


JVMTILocalStorage


jvmti_local_storage


JVMTI本地存储。


jobject


contended_monitor


阻塞本线程的监视器。


jobject


wait_monitor


本线程正在等待的监视器。


jobject *


owned_monitors


本线程拥有的监视器。


int


owned_monitors_nmb


本线程拥有的监视器数量。


apr_pool_t *


pool


本结构体的APR池。


jobject


thread_ref


导致本线程挂起请求的数量。


IDATA


suspend_request


java.lang.Thread实例的弱引用。

线程控制结构的细节参见源代码包中的thread_private.h头文件。

与系附到java.lang.Thread对象上的线程关联的数据结构以及独立(未系附)的线程分别在图 3和图 4中展示。

4.4. 线程组

线程管理器使得多个线程组可以共存,例如,对Java*程序不可见的Java*线程组和GC线程组。每个被线程管理器维护的线程属于一个特定线程组,如图 5所示。



图 5. 线程组

线程管理器提供一套函数用来在特定线程组中迭代遍历线程列表。所有线程被组织在一个线程组数组中,一个特定的系统范围的锁被用来防止对线程组数组以及组中线程列表的并发更改。在创建线程,删除线程以及迭代遍历线程列表时需要首先在内部申请这个锁。

4.5. 同步器

线程管理器同步器是用于线程同步的功能模块。某些同步器有与其自身关联的内部数据结构,其它同步器只能向APR提供的适当的同步器委托函数调用。当前在线程管理器中实现的同步器是基于两个基本原语:条件变量和互斥量,如图 6所示。



图 6. 线程管理器同步器的组件

图中的元素含义如下:

  • APR条件变量(APR conditional variable)和APR互斥量(APR mutex)是Apache Portable Runtime提供的基本原语。
  • TM条件变量(TM conditional variable)和TM互斥量(TM mutex)通过添加wait中断支持包装了相应的APR原语。这些同步器还保证,当使用条件变量将线程置为wait状态或者当线程正在获取一个互斥量时被阻塞,该线程会进入安全挂起模式(safe suspension mode)。
  • Thin监视器(Thin monitor)是一个结合了条件变量的膨胀锁(inflatable lock)。这种结合是构建Java*监视器的基础。
  • 信号量(Semaphore)与POSIX中的信号量相同,也允许指定计数限制。
  • Java*监视器(Java monitor)与java.lang.Object相同。
  • JVMTI 原始监视器(JVMTI raw monitor)是在JVMTI规范中定义的监视器。
  • 暂停(park)和中止暂停(unpark)锁支持原语用在java.util.concurrent包中。

上面的层次是为APR代码复用进行的优化。线程管理器有可能有其它的实现,这些实现可以利用APR同步器的不同集合。

  • 注意: 线程管理器并不将同步器的内部结构暴露给外部组件。访问同步器都需要使用类似于线程控制结构的不透明句柄。

4.6. 监视器

线程管理器的当前版本在实现Java*监视器的时候使用一种特殊的方法处理空间消耗的一般公共问题。DRL线程管理器提供一种特殊类型的监视器——thin监视器;这种监视器持有的锁为空间消耗和单线程的使用提供了优化。

4.6.1. 膨胀技术

监视器膨胀用thin-fat锁技术6]实现,工作过程如下:

  • 在没有线程竞争的情况下,锁数据被存储在若干字节当中,从而可以在分配Java*对象的同时直接分配锁。
  • 无论竞争何时发生,为锁数据分配的若干字节保存一个对fat锁的引用,这个fat锁可以是一个传统的互斥量。

thin监视器的不同实现可以自由选择空间紧缩或其它优化技术(或并不优化)。但是,推荐的做法是当需要节省内存并且线程竞争不是很激烈时就应选用thin监视器。另外推荐的做法是,使用传统的互斥量和条件变量可以在高竞争的情况下获得更好的可伸缩性。线程管理器中的Java*监视器建立在thin监视器之上。这使得线程管理器可以在Java*对象中直接为thin监视器分配锁结构,而且因此Java*监视器的空间利用率大大提高。

4.6.2. 监视器结构

thin监视器是一个实现了锁压缩技术的同步器原语,它可以作为建立Java*监视器[6]的基础。换句话说,thin监视器驻留在TM子系统的native layer,不在Java*对象存放任何数据。Java*监视器与Java*对象是紧耦合的,驻留在TM子系统更高的Java* layer。

同步器的核心内容是锁字(lock word)。锁字持有thin锁值或者对fat锁的引用,这依赖于竞争情况。

在没有竞争的情况下,锁的类型是0,锁字有如下结构:



图 7. 锁字结构:Contention Bit为0

  • Contention bit:0表示没有竞争;
  • Thread ID (15 bits): 持有该锁的线程ID。如果锁未被任何线程持有,则该位为0;
  • Recursion count: 锁被同一个线程反复申请的次数减1;
  • Reservation bit: 指示锁是否被一个线程保留的标志7];
  • 最右边的10 bits在TM中未使用,它们被保留用作存储Java*对象的哈希码。

在有竞争的情况下,contention bit被设置为1,一个thin压缩的锁变成了一个fat膨胀锁,它有如下布局:



图 8. 锁字结构:Contention Bit为1

  • Contention bit: 1表示存在竞争;
  • Fat Lock ID (20 bits): 相应fat锁的ID;
  • Reservation bit: 指示锁是否被一个线程保留的标志7];
  • 最右边的10 bits在TM中未使用,它们被保留用作存储Java*对象的哈希码。

线程管理器用一个张全局锁表实现(译注:fat)锁ID和相关fat监视器之间的映射,如下:



图 9. Thin和Fat监视器的关系

4.6.3. 获取一个监视器

借助hythread_thin_monitor_try_enter()函数可以获取一个监视器,其过程如下图:



图 10. 申请一个Thin锁

首先,线程通过reservation bit检查所需的锁是否已被自己拥有。如果是,线程将recursion count加1,函数退出。这种做法使得单线程程序拥有最快速的monitor enter操作路径。这条快速路径只包含若干汇编指令,而没有高开销的原子比较-交换(compare-and-swap, CAS)操作。

如果锁还没有被保留,检查它的占用情况。如果锁是未被占用的(lock free),将它设置为“已保留”同时以一条CAS操作获得之。如果锁之后变成被占用的(lock busy),系统检查锁是否为fat锁。

锁表持有fat锁ID和实际监视器之间的映射关系。Fat监视器被从锁表中提取出来并被获取。如果锁不是fat并且被另一个线程保留,那么申请锁的线程挂起锁持有者线程,去除保留状态,然后再启动锁持有者线程。之后,再重新尝试获取锁。

5. 使用场景

这一节包括各种线程操作的场景。

5.1. Java* 线程生命期

Java*线程的创建过程包括如下主要步骤:

  1. 在创建了一个线程之后,Thread()构造函数创建一个新的native线程并初始化线程控制结构HyThreadJVMTIThread
  2. 用户应用程序然后调用VM core组件中内核类的java.lang.Thread.start()方法。
  3. java.lang.Thread.start()方法通过java.lang.VMThreadManager.start()函数向线程管理器中的Java* layer的jthread_create()函数委托一个调用。
  4. jthread_create()函数调用jthread_create_with_function()
  5. jthread_create_with_function()函数调用hythread_create()函数,提供wrapper_proc作为一个新线程体的过程。
  6. hythread_create()函数向APR porting layer的apr_thread_create()函数委托一个调用,它本身并不真正fork并创建一个新线程。在这一步,提供{{{wrapper_proc参数作为线程体。
  7. 新创建的线程开始执行thread_start_proc(),这个函数再转而执行wrapper_proc()函数。
  8. 函数wrapper_proc()执行新线程向其它组件的注册请求。方法是通过向VM core发送vm_attach事件,并调用jvmti_send_thread_start_end_event()函数,它会发送JVMTI_EVENT_THREAD_START事件。
  9. wrapper_proc()函数调用java.lang.Thead.run()方法,这个方法即是用户定义的新Java*线程的线程体。
  10. Thread.run()结束之后,线程向其它组件注销。方法是调用jvmti_send_thread_start_end_event()函数会,它会先发送JVMTI_EVENT_THREAD_END事件,然后是vm_detach事件。

下图展示了线程创建和完成的详细过程:



图 11. Java*线程的生命周期

  • 注意:

    native线程控制结构(例如,HyThreadJVMTIThread)并不是在每次新线程结束时都被销毁。线程管理器为每个java.lang.Thread对象创建一个弱引用以提供内部引用队列。当一个特定的java.lang.Thread对象被垃圾回收时,垃圾收集器在那个队列中放置一个引用。在为新线程分配native资源之前,线程管理器在队列中寻找弱引用。一旦弱引用队列非空,线程管理器从队列中提取第一个可用引用并为新建线程复用那个引用的native资源。

5.2. 线程挂起

native layer为APR线程支持添加的一个主要特征是安全挂起(safe suspension)。该机制保证了挂起的线程在活引用枚举期间可以被垃圾收集器安全地探测到。如果线程持有一些系统关键锁,如与本地堆内存关联的锁,安全挂起可以使得这些线程在枚举期间仍然运行。否则,一旦VM的其它部分需要同样的系统锁,使用系统调用或者“hard”调用来挂起线程可能导致死锁。

安全挂起的算法描述了两个线程间的通信协议,例如,有两个线程T1和T2,其中T1安全挂起线程T2。T1调用hythread_suspend(T2)函数来挂起线程T2。该过程步骤如下:

  1. hythread_suspend(T2)函数为线程T2增加指示请求挂起的标志。依赖于T2当前的状态,hythread_suspend(T2)函数执行下面机制中的一个:

    1. 如果线程T2当前运行在安全代码区,hythread_suspend(T2)调用立即返回,如图 12。
    2. 如果线程T2当前运行在非安全代码区,hythread_suspend()在T2到达安全区开始点或者安全点之前都会阻塞。
  2. 线程T2运行到安全区结束点,然后阻塞直到T1调用hythread_resume(T2)恢复它。

线程T2经历如下:

  1. 线程T2周期性地调用hythread_safe_point()函数指定安全挂起点。如果之前有对T2的挂起请求,该方法通知T1然后等待直到T1调用hythread_resume(T2)恢复T2。
  2. 当T2进入安全区,它调用hythread_suspend_ensable()方法,该方法减少suspend_disable_count状态标志。如果之前有对T2的挂起请求,T1会得到T2已经到达安全区的通知。
  3. 当T2离开安全区,它调用hythread_suspend_disable()函数,该函数增加suspend_disable_count状态标志。

一个典型的安全挂起场景的例子发生在垃圾收集器挂起一个Java*线程以便进行活引用枚举的时候。图 12 展示了GC使用线程管理器挂起运行在安全区的Java*线程的情况。



图 12. 挂起:安全区

为了更好地理解安全线程挂起算法,考虑每个线程都有一个锁与之关联。当线程T2进入安全区时释放锁,离开安全区时获取锁。为挂起线程T2,需要获取与之关联的锁。恢复T2等同于释放与之关联的锁。安全挂起算法的一个直观的实现为每个线程保留一个单线程优化的锁(即:thin监视器)并且使用它来挂起和恢复那个线程。

另一个安全挂起情况是当一个GC线程碰到一个运行在非安全代码区的Java*线程,如图13所示。



图 13. 安全点

考虑hythread_safe_point()作为一个在和线程关联的监视器上执行的wait操作。在这种情况下,hythread_resume()等同于通知那个监视器。

5.3. Stop-the-world 线程挂起

当垃圾收集器需要为某个线程组中所有线程枚举活对象引用时,将发生stop-the-world线程挂起。图 14 展示了当只有一个GC线程但是有无数Java*线程在运行时的情况,此时GC需要挂起所有Java*线程。



图 14. 挂起一个线程组

首先,垃圾收集器调用线程管理器接口函数hythread_suspend_all()以便挂起运行在给定线程组中的每一线程(在本示例中,所有Java*线程)。线程管理器随后返回用于遍历被挂起线程列表的迭代器。GC使用该迭代器分析每一Java*线程与活引用的关系,然后进行垃圾回收。完成后,GC通知线程管理器恢复所有线程。

5.4. 线程锁定

涉及线程管理器的锁定可以通过互斥量或者thin监视器的方法实现。互斥量适合用在高度竞争的情况下,而thin监视器对空间进行了更好的优化。本节描述VM core试图锁定来自多个线程T1和T2的资源。锁定和解锁的主要过程如图 15所示。



图 15. 用互斥量锁定

开始,互斥量未被占用,就是说,标签锁被设置为0。线程T1调用hymutex_lock()函数,该函数通知线程管理器标记互斥量表示已经被T1锁定了。

T2也可以在随后调用hymutex_lock(),如果刚好所需的锁已经被占用,T2被放置在内部与互斥量关联的等待队列中,并阻塞直到T1对该互斥量解锁。T1调用hymutex_unlock()释放互斥量,这会使得互斥量从等待队列中提取T2,将锁的所有权授予T2,然后通知T2可以醒来了。

5.5. 监视器的进入和退出

锁定Java*监视器意味着在线程管理器和VM core之间的交互,因为线程管理器需要请求Java*对象中的内存地址,其中保存锁数据。锁定Java*监视器的过程如图 16所示。

如果Java*代码中有同步片段,会有以下步骤:

  1. JIT生成的代码调用线程管理器提供的hythread_monitor_enter()帮助器函数。帮助器函数提供一个代码块(存根),该存根可被JIT直接内联到所生成的汇编码中。
  2. hythread_monitor_enter()帮助器调用VM core组件的vm_object_get_lockword_addr()函数来查找Java*对象中锁字的物理地址。
  3. 帮助器调用thin_monitor_try_lock()函数以便获取对象关联的锁。
  4. 一旦锁被获取,则帮助器返回。这个获取Java*监视器的快速路径。在这个场景下,帮助器不需要在Java*和native帧之间切换,thin_monitor_try_enter()会被直接调用,不涉及任何Java*对象。否则,帮助器代码通过在Java*和native代码之间切换而进入一个慢速路径(参见下图中压入一个M2nFrame并创建本地句柄的动作)。
  5. 帮助器调用jthread_monitor_enter()函数,该函数就像在JNI代码一样与Java*对象协同工作。


图 16. 锁定Java*监视器

6. 参考文献

[1] J2SE 1.5.0 specification, http://java.sun.com/j2se/1.5.0/docs/api/

[2] JVM Tool Interface Specification, http://java.sun.com/j2se/1.5.0/docs/guide/jvmti/jvmti.html

[3] Java* Native Interface Specification, http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/jniTOC.html

[4] Apache Portable Runtime project, http://apr.apache.org/

[5] POSIX standard in threading, http://www.opengroup.org/onlinepubs/009695399/idx/threads.html

[6] David F. Bacon, Ravi Konuru, Chet Murthy, Mauricio Serrano, Thin locks: featherweight synchronization for Java, http://portal.acm.org/citation.cfm?id=277734

[7] Kiyokuni Kawachiya Akira Koseki Tamiya Onodera, Lock Reservation: Java Locks Can Mostly Do Without Atomic Operation, http://portal.acm.org/citation.cfm?id=582433

[8] HyThread documentation, http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/doc/vm_doc/html/group__Thread.html

* Other brands and names are the property of their respective owners.

  • (Contributors: 赵雷([email protected])、张昱([email protected]))

线程管理 (last edited 2009-09-20 21:54:51 by localhost)

  • Immutable Page
  • Info
  • Attachments
  •          
    More Actions:
    Raw Text
     
    Print View
     
    Render as Docbook
     
    Delete Cache
     
    ------------------------
     
    Check Spelling
     
    Like Pages
     
    Local Site Map
     
    ------------------------
     
    Rename Page
     
    Copy Page
     
    Delete Page
     
    ------------------------
     
    My Pages
     
    Subscribe User
     
    ------------------------
     
    Remove Spam
     
    Revert to this revision
     
    Package Pages
     
    Sync Pages
     
    ------------------------
     
    Load
     
    Save
     
    SlideShow
         
时间: 2024-12-18 11:21:22

java线程管理的相关文章

java 线程管理Executors

(1) newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程. 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程. (2) newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待. (3)  newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行. (4) newSingleThread

Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

第一章 Thread导论 为何要用Thread ? 非阻塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Task) 并行算法 第二章 Thread的创建与管理 一.什么是Thread ? Thread是所在主机执行的应用程序任务(task). 只有一个线程的例子: public class Factorial { public static void main(String[] args) { int n = 5; System.ou

java并发编程实战手册(一)线程管理

本文主要是以知识点的形式对java多线程进行了解,学习java多线程的基础,本文参考书籍<java并发编程实战手册>,若有兴趣想研究跟高级的多线程思想,可以阅读<java并发编程实战>. 1.线程的创建和运行 java线程的创建有三种方式,可能大部分人只知道常用的两种: 1.继承Thread类,并且覆盖run()方法. 2.创建一个实现Runnable接口的类.使用带参数的Thread构造器来创建Thread对象. 3.使用Callable与Future来创建启动线程 1.创建Ca

java线程池

1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? 1 new Thread(new Runnable() { 2 3 @Override 4 public void run() { 5 // TODO Auto-generated method stub 6 } 7 }).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过

Java线程休眠(sleep)示例

java.lang.Thread的sleep()方法能使当前线程暂停运行一段时间(单位毫秒).需要注意的是,sleep()方法的参数不能为负,否则会抛出IllegalArgumentException异常. 除此之外,还有另一个方法sleep(long millis, int nanos),该方法可用于使当前线程暂停millis毫秒nanos纳秒.需要注意的是,参数nanos的取值范围为[0, 999999]. 下面的代码演示如何用Thread.sleep()方法令主线程暂停执行2秒. Thre

java内存管理

一.jvm内存结构 程序计数器(Program Counter Register).JVM虚拟机栈(JVM Stacks).本地方法栈(Native Method Stacks).堆(Heap).方法区(Method Area) (1)PCR 跟随线程生命周期,记录当前执行到的.class字节码行数,用于多线程操作 (2)JVM Stacks 跟随线程生命周期,在方法执行中存储数据 (3)Native Method Stacks 处理native方法,如object中的hashCodes()等

Java线程(一)

1. java什么叫线程安全?什么叫不安全? 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问 什么叫线程安全: 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口

java线程池原理及实现方式

线程池的定义 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程 为什么要使用线程池 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.在一个 JVM 里创建太多的线程可能会导致系统由于过度消耗内存而用完内存或"切换过度".为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目. 线程池组成部分 1.线程池管理器(ThreadPoolManager):用于创建并管理线程池,包括 创建线程池,销

干货|宏巍软件之Java线程监控之旅

宏巍软件 许向 大家好,我是上海宏巍信息技术有限公司(简称:宏巍软件)的许向,宏巍软件成立于2005年,是一家以电商ERP软件开发为主的高新技术科技型软件公司,致力于为大型网商和电子商务企业提供专业.全面.量身订制的企业ERP管理软件和应用解决方案. 宏巍电商ERP软件是在阿里体系内使用他们的SLB,然后在ECS上用haproxy JBOSS(多进程)做的集群,ERP端和接口系统都是使用Java语言实现的.随着近年来电商业务量的爆发式增长,Java在性能上的问题逐渐突出,ERP端有时候会无故的卡