Learning the JVM from Scratch series:

Learning from the Ground up ->JVM (Preface)

Learning from the ground up ->JVM (Preface) – Why delay?

JVM (a) : The Java Memory Model (JMM) is not the Java Virtual Machine memory model (JVM) oh!

Learning from the Ground up – JVM part 2: Why does Java Need a JVM (Java Virtual Machine)?

Learning from the Ground up ->JVM (3) : Classloader (1)

Learning from the Ground up ->JVM (4) : Classloader (Middle)

Learning from the ground up ->JVM (5) : Classloader (2)

Learning from the Ground up – JVM part 6: The Relationship between threads and JVMS

Learning from the ground up ->JVM (7) : Runtime Data Area (1)

Learning from the ground up ->JVM (8) : Runtime Data area (2)

Learning from scratch ->JVM (9) : Garbage Collection (1)

Learning from the ground up ->JVM (10) : Garbage Collection (middle)

Learning from scratch ->JVM (11) : Garbage Collection (2)

preface

In front of the Class loader articles, we can see that the Class loader by Java Class bytecode file, create a Class object, and through the load – validation – to – resolution – initialization and a series of process, the Java classes loaded into the JVM, until this time, the JVM will transfer the ownership to the Java application.

At this point, our Java program is ready to run.

When a Java program starts to run, threads and objects are created and die as the program runs out. The creation and death of objects is definitely related to runtime data areas in the JVM, but today we’ll leave that out and take a deeper look at threads.

The body of the

A JVM is a virtual machine, that is, it must run on an operating system, whether Linux or Windows.

While operating systems provide threading implementations, the Java language provides uniform handling of threading operations on different hardware and operating system platforms. Each instance of the java.lang.Thread class that has called the start() method and has not yet terminated represents a Thread.

We noticed that the Thread class was significantly different from most Java library apis in that all of its key methods were declared Native. In Java library apis, a Native method often means that the method is not implemented or cannot be implemented using platform-independent means.

Thread native method source code is as follows:

Public class Thread implements Runnable {// Make sure that calling the registerNatives method is the first thing to do upon initialization. private static native void registerNatives(); static { registerNatives(); } private volatile String name; private int priority; private Thread threadQ; private long eetop; public synchronized void start() { if (threadStatus ! = 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (! started) { group.threadStartFailed(this); }} catch (Throwable ignore) {}}} private native void start0(); Private native Boolean isInterrupted(Boolean ClearInterrupted); // Tests whether this thread is active. public final native boolean isAlive(); // Count the stack frames in this thread. (The thread must be suspended.) @Deprecated public native int countStackFrames(); Public static native Boolean holdsLock(Object obj); public static native Boolean holdsLock(Object obj); private native static StackTraceElement[][] dumpThreads(Thread[] threads); private native static Thread[] getThreads(); private native void setPriority0(int newPriority); Private native void stop0(Object o); private native void stop0(Object o); private native void suspend0(); private native void resume0(); private native void interrupt0(); private native void setNativeName(String name); }Copy the code

From this code, we can see that Java threads are created not by the Java program itself, but by the underlying operating system. The Operation call of Java program to the thread is not directly called by Java program, but indirectly by calling the interface provided by the operating system.

And all of this has nothing to do with our Java virtual machine.

Of course, the Java virtual machine provides the model and solution to support the operating system scheduling, but the Java virtual machine only does this, which is equivalent to doing a transfer operation, the Java program about thread creation and operation, the operating system.

Operating system thread implementation

And the underlying operating system, thread implementation mainly has three ways: the use of kernel thread implementation (1:1 implementation), the use of user thread implementation (1: N implementation), the use of user thread and lightweight process mixed implementation (N: M implementation). Details are as follows:

1. Kernel threads

The implementation using kernel threads is also known as a 1:1 implementation. Kernel-level threads (KLT) are threads directly supported by the operating system Kernel. These threads are switched by the Kernel, which manipulates the Scheduler to schedule the threads. And is responsible for mapping the tasks of the thread to the individual processors.

Each Kernel thread can be viewed as a doppelgant of the Kernel, so that the operating system can handle more than one thing at a time. A Kernel that supports multithreading is called a multi-threads Kernel.

Generally, programs do not directly use kernel threads, but use a high-level interface of kernel threads — light-weight Process (LWP). Lightweight processes are generally referred to as threads. Since each lightweight Process is supported by a kernel thread, kernel threads must be supported first. To have lightweight processes. This 1:1 relationship between lightweight processes and kernel threads is called the one-to-one threading model.

2. User thread:

The approach of using the user thread implementation is known as the 1: N implementation.

Broadly speaking, a Thread as long as it’s not a kernel Thread, can be considered a User Thread a User Thread, (UT), so look from this definition, a lightweight process also belong to the User Thread, but the realization of lightweight process is always based on the kernel, should undertake many operating system calls, so efficiency could be limited, Does not have the usual benefits of user threads.

In the narrow sense, user thread refers to a thread library that is completely built in user space, and the system kernel cannot perceive the existence of user thread and how to achieve it. The creation, synchronization, destruction, and scheduling of user threads are complete in user mode without the help of the kernel. If implemented properly, this thread does not need to be switched to kernel mode, so operations can be very fast and low cost, and can support a larger number of threads. Some of the multi-threading in high performance databases is implemented by user threads.

The advantage of the user thread is that it does not need the support of the system kernel, and the disadvantage is that there is no support of the system kernel. All thread operations need to be handled by the user program itself.

Java previously supported user threads, but later abandoned them.

3. Hybrid implementation:

In addition to relying on the kernel thread implementation and completely implemented by the user program itself, there is another implementation that uses the kernel thread and user thread together, which is called N: M implementation.

Under this hybrid implementation, there are both user threads and lightweight processes. User threads are still built entirely in user space, so user threads are still cheap to create, switch, and destruct, and can support large-scale user thread concurrency. The lightweight process supported by the operating system acts as a bridge between the user thread and the kernel thread, so that the thread scheduling function and processor mapping provided by the kernel can be used, and the system call of the user thread is completed through the lightweight process, which greatly reduces the risk of the entire process being completely blocked.

The threading model of the JVM

Since JDK 1.3, the threading model for “mainstream” commercial Java virtual machines on “mainstream” platforms has generally been replaced with one based on the operating system native threading model, with a 1:1 threading model (kernel threading).

That is, Java threads in the JVM have a direct mapping to native operating system threads.

When Java thread local storage, buffer allocation, synchronous objects, stacks, program counters, and so on are ready, an operating system native thread is created. The operating system is responsible for scheduling all threads and allocating them to any available CPU. When the native thread completes initialization, the Java thread’s run() method is called. When the thread terminates, all resources of the native thread and Java thread are released.

So, what threads are involved in running Java programs, and how do you subdivide those threads?

First, the JVM finds the program’s entry point, main(), and then runs the main() method, creating a thread called the main thread. When the main method ends, the main thread completes. The JVM process also exits (starting a Java program generates a JVM process). In addition to the main thread generated by the main method, the Java program also generates other threads, which are what we call multithreaded programming threads.

Of course, in addition to these threads, if you use JConsole or any debugging tool, you will see many threads running in the background. These background threads do not include the main thread that calls public static void main (String []) and all threads created by the main thread itself.

The main backend threads in the Hotspot JVM are:

  1. Virtual machine threads: These thread operations do not occur until the JVM has reached a safe point. The reason these operations must occur in different threads is that they all need the JVM to reach a safe point so that the heap does not change. The types of execution of this thread include “stop-the-world” garbage collection, thread stack collection, thread suspension, and biased lock cancellation.
  2. Periodic task threads: These threads are representations of periodic events (such as interrupts) and are typically used for scheduled execution of periodic operations.
  3. GC thread: This thread provides support for different kinds of garbage collection behavior within the JVM.
  4. Compile thread: This thread compiles bytecode to native code at run time.
  5. Signal scheduling thread: This thread receives a signal well and sends it to the JVM for processing within it by calling the appropriate method.

The JVM is safe when the heap in the JVM satisfies either of the following two points:

1. Heap memory changes are controlled and it is best to stop all threads.

2. Objects in the heap are known. Objects that are no longer used are difficult to find or cannot be found, that is, the state of objects in the heap is known.

The combination of all these threads makes up an entire Java program and JVM ecosystem.

conclusion

It is difficult to describe the situation of threads in the JVM, because the point itself is just to illustrate that threads are very closely related to the JVM.

However, for this article, threads themselves are not connected to our JVM, but to the creation and destruction of objects during the running process of the thread.

So this relationship between the JVM and threads is something that we really need to understand and explore. Of course, this article is relatively shallow understanding of the relationship between them, I hope to have time to clarify the point later.

I’ll stop there.