并发编程的历史综述与最新进展以及在HotSpot中的具体实现

ZHH2009 2014-08-04
群里有关多线程并发同步的贴子也有一些,但是还是缺乏系统性,也缺乏深度,
开这个贴,希望集中讨论有关多线程的主题,把所有细节讨论清楚。


此贴记录与并发编程相关的历史综述与最新进展以及在HotSpot中的具体实现。

目前我在HotSpot中研究并发和GC两大模块,会不定期更新此贴的内容。
ZHH2009 2014-08-04
下面这些书对于这个主题有一些帮助:

入门类:
------------
【Java核心技术(卷I)】 http://book.douban.com/subject/3146174/

第14章 多线程


【Java线程】 http://book.douban.com/subject/1768767/


进阶类:
------------
【深入理解Java虚拟机 : JVM高级特性与最佳实践】 http://book.douban.com/subject/24722612/
第12、13章

【java并发编程实战】 http://book.douban.com/subject/10484692/

【多处理器编程的艺术】 http://book.douban.com/subject/24700553/

【Windows并发编程指南】 http://book.douban.com/subject/4214617/

后续补充……
ZHH2009 2014-08-04
HotSpot中与这个主题相关的实现代码
(这里基于OpenJDK 8的代码 http://hg.openjdk.java.net/jdk8/jdk8/tags):

多数代码都归到runtime模块(hotspot\src\share\vm\runtime),
-----------------------------------------------
basicLock
biasedLocking
monitorChunk
mutex
mutexLocker
objectMonitor
os
osThread
park
synchronizer
thread
vmThread
-----------------------------------------------

归到interpreter模块(hotspot\src\share\vm\interpreter)的有:
-----------------------------------------------
interpreterRuntime中的monitorenter和monitorexit
TemplateTable::monitorenter
TemplateTable::monitorexit
TemplateTable::_return
AbstractInterpreterGenerator::generate_method_entry(zerolocals_synchronized)
-----------------------------------------------

归到classfile模块(hotspot\src\share\vm\classfile)的有:
-----------------------------------------------
javaClasses中的java_lang_Thread和java_lang_ThreadGroup类
-----------------------------------------------

归到oops模块(hotspot\src\share\vm\oops)的有:
-----------------------------------------------
markOop
-----------------------------------------------


归到prims模块(hotspot\src\share\vm\prims)的有:
-----------------------------------------------
jvm
unsafe


JDK层的相关代码:
java code
---------------------
jdk\src\share\classes\java\lang\Object.java

jdk\src\share\classes\java\lang\Runnable.java
jdk\src\share\classes\java\lang\Thread.java
jdk\src\share\classes\java\lang\ThreadDeath.java
jdk\src\share\classes\java\lang\ThreadGroup.java
jdk\src\share\classes\java\lang\ThreadLocal.java

native code
---------------------
jdk\src\share\native\java\lang\Object.c
jdk\src\share\native\java\lang\Thread.c
ZHH2009 2014-08-04
这楼说明java.lang.Thread如何对应到jvm、os层的线程,
以及java线程初始化和启动过程

对于下面的代码:
public class ThreadTest {
    public static void main(String[] args) {
        Thread t = new Thread();
        t.start();
    }
}

在Thread t = new Thread()这一步还没有在HotSpot中创建或启动相关的线程,
而是在t.start()这一步才开始。


Thread.start的代码
public synchronized void start() {
        //......
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
        //......
}

其中的start0是一个native方法,除了start0外,还有stop0、suspend0等等,
这些native方法通过jdk\src\share\native\java\lang\Thread.c关联到hotspot\src\share\vm\prims\jvm.cpp
//jdk\src\share\native\java\lang\Thread.c
static JNINativeMethod methods[] = {
    {"start0",           "()V",        (void *)&JVM_StartThread},
    {"stop0",            "(" OBJ ")V", (void *)&JVM_StopThread},
    {"isAlive",          "()Z",        (void *)&JVM_IsThreadAlive},
    {"suspend0",         "()V",        (void *)&JVM_SuspendThread},
    {"resume0",          "()V",        (void *)&JVM_ResumeThread},
    {"setPriority0",     "(I)V",       (void *)&JVM_SetThreadPriority},
    {"yield",            "()V",        (void *)&JVM_Yield},
    {"sleep",            "(J)V",       (void *)&JVM_Sleep},
    {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},
    {"countStackFrames", "()I",        (void *)&JVM_CountStackFrames},
    {"interrupt0",       "()V",        (void *)&JVM_Interrupt},
    {"isInterrupted",    "(Z)Z",       (void *)&JVM_IsInterrupted},
    {"holdsLock",        "(" OBJ ")Z", (void *)&JVM_HoldsLock},
    {"getThreads",        "()[" THD,   (void *)&JVM_GetAllThreads},
    {"dumpThreads",      "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
    {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};

//这里的jclass cls对应java.lang.Thread
//TODO HotSpot内部如何解析native方法?
JNIEXPORT void JNICALL
Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
}


上面以JVM开头的方法都在hotspot\src\share\vm\prims\jvm.cpp中,
例如java.lang.Thread类的start0方法对应JVM_StartThread方法:
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;

  // We cannot hold the Threads_lock when we throw an exception,
  // due to rank ordering issues. Example:  we might need to grab the
  // Heap_lock while we construct the exception.
  bool throw_illegal_thread_state = false;

  //......

JVM_END

如果想跟踪线程的创建和启动过程,就可以在JVM_StartThread打断点来跟踪调试。



后续补充......

理清java.lang.Thread和HotSpot中的JavaThread、OSThread之间的关系,
每个java.lang.Thread都由一个JavaThread对象表示,
对于OSThread要分不同os来描述,
在Windows里,每个OSThread都代表了一个Windows线程(通过_beginthreadex来创建)。
ZHH2009 2014-08-04
synchronized方法和synchronized块在字节码级的简单介绍
ZHH2009 2014-08-04
Object.wait/notify的一些疑惑

当线程A执行Object.wait后,
另一线程B执行完notify,并不会马上触发通知事件,
而是在退出同步块或同步方法执行到InterpreterRuntime::monitorexit时,
这就解释了Object.notify()的java doc中那句话:The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object

同步块由monitorexit字节码对应的汇编代码触发InterpreterRuntime::monitorexit,
同步方法通常对应一条return或Xreturn字节码,它们对应的汇编代码也会触发InterpreterRuntime::monitorexit。

对于上面存在一种例外,
HotSpot VM提供了一个SyncKnobs配置参数,可以在执行notify时提前发出通知事件,
像这样配置: SyncKnobs="MoveNotifyee=5"

ZHH2009 2014-08-04
HotSpot VM中在实现Object.notify时是如何选择要唤醒的线程的?

如果有多个线程在等待,要唤醒哪个线程其实是看哪个线程先执行wait的,
每次Object.notify只选择第一个执行wait的那个线程。


具体代码在ObjectMonitor::AddWaiter/DequeueWaiter/DequeueSpecificWaiter
ZHH2009 2014-08-04
占楼......
ZHH2009 2014-08-04
占楼......
ZHH2009 2014-08-04
占楼......
Global site tag (gtag.js) - Google Analytics