摘要
由于Java的并发和线程息息相关,我们今天看一下线程的实现方式,通用的线程实现方式有:
1. 内核线程
内核线程(KLT)其实就是直接由操作系统内核支持的线程,这种线程由内核完成切换。内核通过调度器对线程进行调度,将线程映射到处理器上。
在我们程序的实际使用中,不会直接去使用内核线程,而是使用内核线程的一种高级接口——轻量级进程(LWP),轻量级进程就属于我们常说的线程。轻量级进程和内核线程是1:1的关系。
由于内核线程的支持,每一个轻量级进程都是一个可以独立的调用单元,由于轻量级进程基于内核线程实现,内核线程直接由操作系统控制,所以我们可以不用线程的创建、切换、调度、阻塞,几乎所有的线程操作都可以交由操作系统内处理。
轻量级线程的缺点就是,我们的操作系统如果要使用轻量级进程必须要进行系统调用,系统调用需要在用户态和内核态进行切换,调用代价相对较高。其次每个轻量级进程对应一个内核线程,因此会占用一定的内核资源,因此一个操作系统支持轻量级进程的数量是有限的。
2. 用户线程
用户线程指的是完全建立在用户空间的线程库上,系统内核不能感知线程的存在。用户线程的所有操作都在用户态中完成,不需要内核的帮助。
用户线程的优点是不需要进行系统调用,调用代价低,缺点就是用户需要自己维护线程的创建、调度、同步、阻塞等操作,实现代价相对较高。
3. 用户线程+轻量级进程
用户线程+轻量级进程就是采用了上述两种实现的结合,通过这种结合我们可以取其精华去其糟粕。
首先用户线程是完全建立用户空间,用户线程的创建、切换调用代价较低,并且可以支持大规模的并发。
轻量级进程是用户线程和内核线程的之间的桥梁,通过轻量级进程,我们可以使用内核提供的线程调度功能和处理器映射(实现代价相对较高的操作)。在这种混合模式中,用户线程和轻量级进程的比例关系为N:M。
4. Java线程实现
Java线程的实现方式就是采用用户线程+轻量级进程混合的模式,Java线程和轻量级进程的比例关系为1:1,至于为什么是1:1,我们可以分析一下:
我们在使用Java的Thread时,会调用start方法开启一个线程。
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
在start方法中有个关键的方法就是start0(),然后该方法是个native方法,这时候我们就需要看一下JDK的源码实现了,关于这个start0方法是在源码文件./jdk/src/share/native/java/lang.Thread.c中,如下图:
我们可以看到,start0方法实际上执行的JVM_StartThread方法,该方法所在的文件是./hotspot/src/share/vm/prims/jvm.cpp。
上图中JVM_StartThread方法中我们会new一个JavaThread,然后我们看一下这个JavaThread的实现, JavaThread的类定义在./hotspot/src/share/vm/runtime/thread.cpp中,如下图:
os::create_thread(this, thr_type, stack_sz);这里就是各个操作系统去创建线程了,这里我们假设我们的操作系统是linux操作系统,create_thread的方法存储在,./hotspot/src/os/linux/vm/os_linux.cpp中,linux中的线程创建方式是pthread,在create_thread方法中最终会有如下代码,完成轻量级进程的创建,如下:
通过上述分析,我们可以看到,在Java中每创建一个线程,我们变会创建一个轻量级进程,所以Java中的用户线程和轻量级进程为1:1。
本期的Java线程实现介绍到这,我是shysh95,顺手关注+在看,我们下期再见!!!
往期推荐