java同步机制之thread模型-part3

Posted by My Blog on June 5, 2021

1.green threads

所谓绿色线程或者虚拟线程,是指由虚拟机或者程序库自行实现。java1.2(含)以前使用的即为绿色线程,1.3之后切换为native 线程,即底层操作系统线程

In computer programming, green threads or virtual threads are threads that are scheduled by a runtime library or virtual machine (VM) instead of natively by the underlying operating system (OS). Green threads emulate multithreaded environments without relying on any native OS abilities, and they are managed in user space instead of kernel space, enabling them to work in environments that do not have native thread support

Green threads refers to the name of the original thread library for the programming language Java (that was release in version 1.1 and then Green threads were abandoned in version 1.3 to native threads). It was designed by The Green Team at Sun Microsystems

详见Green threads

2.hotspot 线程模型1

hotspot虚拟机中java线程(java.lang.Thread)跟底层操作系统线程是1:1映射的,java线程由操作系统进行调度。对于linux操作系统,其线程实现采用NPTL

1
NPTL (Native POSIX Threads Library) is the GNU C library POSIX threads implementation that is used on modern Linux systems

类似进程轻量级fork()机制实现,完全由os scheduler调度分配。通过ps -eLf,可以查看java进程和线程的关系

3.java,jvm和操作系统线程关系2

其中JavaThread,OSThread由hotspot用c++实现,并持有java.lang.thread对象

OSThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class OSThread: public CHeapObj<mtThread> {
 private:
  OSThreadStartFunc _start_proc;  // Thread start routine
  void* _start_parm;              // Thread start routine parameter
  
 public:
  OSThread(OSThreadStartFunc start_proc, void* start_parm);
  ~OSThread();

  // Platform dependent stuff
#ifdef TARGET_OS_FAMILY_linux
# include "osThread_linux.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "osThread_windows.hpp"
#endif
...

osThread_linux

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef OS_LINUX_VM_OSTHREAD_LINUX_HPP
#define OS_LINUX_VM_OSTHREAD_LINUX_HPP
 public:
  typedef pid_t thread_id_t;

 private:
  int _thread_type;

 public:

  int thread_type() const {
    return _thread_type;

thread.hpp

1
2
3
4
5
6
class Thread: public ThreadShadow {
  friend class VMStructs;

protected:
  // OS data associated with the thread
  OSThread* _osthread;  // Platform-specific thread information

JavaThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Class hierarchy
// - Thread
//   - NamedThread
//     - VMThread
//     - ConcurrentGCThread
//     - WorkerThread
//       - GangWorker
//       - GCTaskThread
//   - JavaThread
//   - WatcherThread

class JavaThread: public Thread {
  friend class VMStructs;
 private:
  JavaThread*    _next;                          // The next thread in the Threads list
  oop            _threadObj;                     // The Java level thread object
 
 // JSR166 per-thread parker
 private:
   Parker*    _parker;
 public:
   Parker*     parker() { return _parker; }
 ......

上面JavaThread即为jdk中java.lang.Thread在jvm内部的实现,其中_threadObj就保存了java层面的java.lang.Thread对象实例。另外一个重要成员变量就是_parker,它支持了AQS内部实现线程在等待加锁时的休眠和唤醒,后续文章会进一步分析。

4.vm视角的线程状态

  • _thread_new: a new thread in the process of being initialized
  • _thread_in_Java: a thread that is executing Java code
  • _thread_in_vm: a thread that is executing inside the VM
  • _thread_blocked: the thread is blocked for some reason (acquiring a lock, waiting for a condition, sleeping, performing a blocking I/O operation and so forth)

为了debug方便,还支持额外状态

  • MONITOR_WAIT: a thread is waiting to acquire a contended monitor lock
  • CONDVAR_WAIT: a thread is waiting on an internal condition variable used by the VM (not associated with any Java level object)
  • OBJECT_WAIT: a thread is performing an Object.wait() call

4.1 虚拟机内部的不同线程

对于“hello world”这样简单的java程序,在jvm内部也会启动很多线程

  • VM thread: This singleton instance of VMThread is responsible for executing VM operations, which are discussed below
  • Periodic task thread: This singleton instance of WatcherThread simulates timer interrupts for executing periodic operations within the VM
  • GC threads: These threads, of different types, support parallel and concurrent garbage collection
  • Compiler threads: These threads perform runtime compilation of bytecode to native code
  • Signal dispatcher thread: This thread waits for process directed signals and dispatches them to a Java level signal handling method

4.2 VM Operations and Safepoints

虚拟机将所有线程维护在Threads_list里,由Threads_lock来同步

所有java代码在JavaThread线程内执行,虚拟机操作在VMThread执行

何谓Safepoints,垃圾回收中stop the world即为safepoint,此时虚拟机等待其它线程都被block,并取得Threads_lock,然后执行相关操作

其它的vm operation包括:偏向锁操作, 线程栈 dump, 线程中止等

5. java.lang.Thread

  • start, run

  • sleep, join, yield

  • stop, suspend

    Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked. If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior

    stop主要问题是有可能造成数据不一致情况,所以已经不建议使用

  • interrupt3 4

  • ThreadLocal

上述API中,主要讨论一下interrupt实现5,其它可管窥。

5.1 interrupt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker; // *A
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

上面说stop方法已不建议使用,而对interrupt0的注释也仅是just set the flag,标记而已。这意味着,被中断线程其run方法必须自行检测中断状态,否则就会继续执行下去。别人对中断标记,是可以爱搭不理的。此外A处blocker仅在NIO场景下才有使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	// can not be interrupted
	Thread abnormal = new Thread(() -> {
            System.out.println("abnormal thread start");
            int i = 0;
            while (true) { i++;}
        }, "abnormal_thread");
        
        // interruptible
        Thread normal = new Thread(() -> {
            System.out.println("normal thread start");
            int i = 0;
            while (!Thread.currentThread().isInterrupted()) { i++;}
             System.out.println("normal thread end");
        }, "normal_thread");

        normal.start();
        TimeUnit.MILLISECONDS.sleep(100);
        normal.interrupt();

5.1.1 interrupt0 in jvm

jdk/src/share/native/java/lang/Thread.c

image

jdk8u/hotspot/src/os/linux/vm/os_linux.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void os::interrupt(Thread* thread) {
  assert(Thread::current() == thread || Threads_lock->owned_by_self(),
    "possibility of dangling Thread pointer");

  OSThread* osthread = thread->osthread();

  if (!osthread->interrupted()) {
    // 设置中断标记
    osthread->set_interrupted(true);
    OrderAccess::fence();
    ParkEvent * const slp = thread->_SleepEvent ;
    // 1.唤醒休眠
    if (slp != NULL) slp->unpark() ;
  }

  // For JSR166. Unpark even if interrupt status already was set
  if (thread->is_Java_thread())
  	// 2.唤醒同步
    ((JavaThread*)thread)->parker()->unpark();

  ParkEvent * ev = thread->_ParkEvent ;
  // 3.唤醒同步
  if (ev != NULL) ev->unpark() ;

}

拿linux操作系统为例,interrupt主要做了两件事:

  • 设置中断标记
  • 唤醒休眠和同步等待

更详尽解释可参考6,至于unpark干了什么,后续文章会进行分析。

6.协程

jdk后续引入了协程概念,后面有时间再介绍。

7.参考