This is the 7th day of my participation in the August Text Challenge.More challenges in August
First of all, the emergence of multithreading is to speed up the efficiency of the processing tasks, combined with the said before the introduction of the underlying CPU we can know that the operating system level, the threads are the smallest units of the operating system task scheduling, process is the smallest unit of distribution of resources, a process can contain multiple threads, thread in the process of the sharing of resources.
To put it figuratively, processes are like operations in a large factory, and threads are the production lines in the factory. When I say tasks below, I mean the production lines corresponding to threads.
In our Java projects, there may be tasks that we can separate and execute independently, and this introduces the concept of threads. Since everything is an object, Threads are defined in Java to represent threads.
But having said that threads are created to perform tasks, how do you represent specific tasks in Java? Java provides Runnable and Callable interfaces, and the specific task logic is implemented by itself.
There is only one Thread implementation in Java, that is, the Thread class, and all the other tasks are tied to threads. However, be understanding and be careful to say that there is only one way.
At the Java level, it’s easy to inherit Thread and call the start method, but what about at the JVM and operating system level?
The JVM implements multithreading using C++ programming language, and the specific implementation is still dependent on different operating systems. More work is still done in dealing with thread safety, which we discussed last time and can be seen in the design of the JMM.
There are three main ways for operating systems to implement multithreading: kernel thread implementation, user thread implementation and user thread plus lightweight process hybrid implementation.
Implemented using kernel threads
KLT (kernel-level threads) are threads directly supported by the operating system Kernel (Kernel). Thread switching is done by the kernel, which schedules threads through a Scheduler and maps their tasks to the processors. Each kernel thread can be seen 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 multithreaded kernel.
Instead of using kernel threads directly, programs use an advanced interface of kernel threads called Lightweight processes (LWP), or threads in general. Since each lightweight process is supported by a kernel thread, there can be no lightweight process until kernel threads are supported first. The 1:1 relationship between lightweight processes and kernel threads is called the one-to-one threading model.
Advantages: In multi-processor systems, the kernel can schedule concurrent execution of multiple threads in the same process at the same time; If a thread of a process is blocked, the kernel can schedule other threads of that process to run, and it can schedule threads of other processes to run. The thread switching is fast and the switching cost is small. The kernel itself can also adopt multithreading technology, which can improve the speed and efficiency of the system.
Disadvantages: for the scheduling of user threads, its mode switching overhead is relatively large. In the same process, when switching from a thread to another thread, it is necessary to switch from user mode to core state. This is because threads run in user mode, while thread scheduling and management are implemented in the kernel, so the system overhead is relatively large.
Implemented using user threads
User threads are implemented in User space. The creation, cancellation, communication, synchronization and other functions of threads are implemented without the support of the kernel, so the kernel is completely unaware of the existence of user-level threads. The process has a one-to-many relationship with the user thread.
Thread switching does not need to go to kernel space. For a process, all its thread management data structures are in the process’s own user space, and the thread library for managing thread switching also runs in the user address space, so there is no need to switch to the kernel mode to manage threads, which saves the switching overhead between the kernel mode and user mode.
And because of the creation, cancellation, communication, synchronization and other functions of the thread does not need the kernel to complete, need to process their own user procedures, user procedures are generally more complex, so, in this way to deal with the creation of multithreading procedures less and less.
Use a mix of user threads and lightweight processes
In this mode, there are both user threads and lightweight processes. User threads are still built entirely in user space, so user thread creation, switching, and other operations are still cheap, and large-scale user thread concurrency is supported.
Lightweight processes supported by the operating system act as a bridge between user threads and kernel threads, which can use the thread scheduling function provided by the kernel to handle the mapping in time, and the system of user threads is completed by lightweight processes, greatly reducing the risk of the whole process being completely blocked. In this hybrid mode, the ratio of user threads to lightweight processes is an indeterminate N:M relationship.
The above three ways of creating processes are likely to be used by different operating systems, and which one is used in Java depends on the JVM implementation.
Java Threads were implemented based on user Threads called Green Threads prior to JDK 1.2, where the threading model was replaced with an operating system native threading model.
Therefore, in the current JDK version, the operating system supports a thread model that largely determines how Java virtual machine threads are mapped. There is no agreement between platforms on this, and the virtual machine specification does not specify which thread model Java threads need to implement.
For the Sun JDK, both the Windows and Linux versions are implemented using a one-to-one threading model, where a Java thread maps into a lightweight process because of the one-to-one threading model provided by Windows and Linux systems.
The Solaris JDK provides two platform-specific vm parameters: -xx: +UseLWPSynchronization (default) and -xx: +UseBoundThreads specifies exactly which thread model the virtual machine will use.
Related recommendations:
Thoroughly understand the memory structure in the CPU
Java Memory model, one article is enough!