Java线程知识拾遗

知识回顾

进程与线程是经常被提到的两个概念。进程拥有独立的代码段、数据空间,线程共享代码段和数据空间,但有独立的栈空间。线程是操做系统调度的最小单位,一般一个进程会包含一个或多个线程。多线程和多进程均可以实现并发处理,如 nginx 使用多进程方式、tomcat 使用多线程方式、Apache 支持混合使用。在 C/C++ 等语言中能够同时使用多进程和多线程,而在 Java 中只能使用多线程。nginx

在 Java 中,建立线程的惟一方式是建立 Thread 类的实例,调用实例的 start() 方法启动线程。程序员

 

Java 线程实现

在 JDK 1.2 以前,Java 使用用户线程实现 Java 线程,在 JDK 1.2 及以后,Java 基于操做系统原生的线程模型实现 Java 线程。tomcat

使用用户线程( User Thread, UT ) 实现,是指线程创建在用户态空间,线程的创建、同步、调度与销毁都在用户态完成,进程与用户线程之间是1 : N 的对应关系。这种状况下,内核没法知道有多少个用户线程,实现较为复杂。安全

使用内核线程实现,是指基于轻量级进程( Light Weight Process, LWP ) 来实现线程。每一个轻量级进程都有一个内核线程( Kernel-Level Thread, KLT ) 支持,与内核线程之间是 1 : 1 的对应关系。这种状况下,调度线程时可能须要在内核态和用户态之间进行切换。因为轻量级进程须要消耗内核资源,可以支持的线程数量是有限的。微信

如在 Windows 和 Linux 系统中,操做系统原生的线程模型是 1 : 1 的对应关系,对于 Sun JDK 来讲,一个 Java 线程就对应着一个轻量级进程。多线程

 

线程调度与状态

在 Java中线程的调度方式是抢占式调度,即由系统来负责各个线程的时间分配,并在线程使用完分配的时间后调度下一个线程。任何一个线程都不能独占 CPU 。Java 语言一共设置了 10 个线程优先级,当两个线程同时等待执行时,优先级高的先被调度。线程的优先级会被映射到操做系统原生线程上去,但各个操做系统的优先级划分不彻底同样,所以两个优先级不一样的 Java 线程在操做系统中执行时也可能处于相同的优先级。并发

Java 定义了 5 种线程状态,分别是新建 ( New )、运行 ( Running )、等待 ( Waiting )、限期等待 ( Timed Waiting )、阻塞 ( Blocked ) 和结束 ( Terminated )。任一时刻,线程都处于 5 种状态中的一种,并在各个状态之间切换,如图所示。框架

 

其中,各个状态含义以下:分布式

新建:建立后未启动;post

运行:对于 Java 来讲,线程已经运行,但对于操做系统来讲,可能在运行或等待;

等待:线程等待被其余线程唤醒,如调用了 wait、join 且没有指定超时时间;

限期等待:线程等待一段时间后被系统唤醒,如调用了 sleep、wait、join 并设置了超时时间;

阻塞:线程进入同步区域须要与其余线程协调同步,如须要进入 synchronized 区域但其余线程还没有退出此区域;

结束:run 方法执行完成后,线程结束。

 

虚拟机栈

在 Java 内存模型中,每一个虚拟机线程都有本身私有的虚拟机栈。栈与线程同时建立,其中存储的是线程的栈帧 ( Stack Frame )。每一个方法的调用,都对应着一个栈帧的入栈和出栈。在栈帧中,存储着局部变量表 ( Local Variable Table )、操做栈 ( Operand Stack )、动态链接 ( Dynamic Linking )、返回地址 ( Return Address ) 和其余附加信息。

 

线程的工做内存

在内存模型中,Java 要求全部的变量都必须存储在主内存中,每一个线程拥有本身的工做内存。工做内存中保存了线程须要读写的变量的主内存的副本。线程对变量的读写操做都在工做内存中直接进行,并不会去操做主内存中的内容,主内存与工做内存的同步由虚拟机完成。不一样线程不能访问彼此的工做内存,变量值的传递须要通过主内存才能完成。

Volatile 修饰的变量能够保证变量对全部线程可见,即某个线程修改变量后,其余线程总能马上读到新值。即使如此,多线程并发时,对 volatile 变量进行自增自减操做也不能保证线程安全。

 

总结

线程在 Java 中只能经过建立 Thread 类的实例来建立。在 JDK 1.2 以后,Java 中的线程基于操做系统原生的线程模型来实现线程。线程的调度方式是抢占式调度,即由系统来负责各个线程的时间分配,并在线程使用完分配的时间后调度下一个线程。Java 定义了 5 种线程状态:新建、运行、等待、限期等待、阻塞和结束。

每一个虚拟机线程都有本身私有的虚拟机栈。栈与线程同时建立,其中存储的是线程的栈帧。每一个方法的调用,都对应着一个栈帧的入栈和出栈。每一个线程拥有本身的工做内存,工做内存中保存了线程须要读写的变量的主内存的副本。线程对变量的读写操做都在工做内存中直接进行,并不会去操做主内存中的内容,主内存与工做内存的同步由虚拟机完成。

每周 3 篇学习笔记或技术总结,面向有必定基础的 Java 程序员,内容涉及 Java 进阶、虚拟机、MySQL、NoSQL、分布式计算、开源框架等多个领域。关注做者或微信公众号 backend-develop 第一时间获取最新内容。

 

原文地址:Java线程知识拾遗

相关文章
相关标签/搜索