被面试官问到线程基础,这样答满分

笔者把整个java生态分为多个模块,java并发编程是其中一个重要的模块,本篇讲的就是java并发编程模块中的线程基础

java并发编程在整个java生态中的地位举足轻重,贯穿整个java开发应用过程以及面试流程中,而在并发编程中,线程是其基础,要想掌握并发编程的精髓,必须先精通线程基础,本篇就带你搞清楚线程到底是什么?


线程概念

虽然我知道很多读者的基础已经很好,但是为了篇幅的完整性,我还是先要把线程概念阐述出来。

进程

进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

扩展

我们知道,线程是比进程更轻量级的调度执行单位,操作系统把处理器资源分配给进程,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度。目前线程是Java里面进行处理器资源调度的最基本单位,不过如果日后引入纤程(Fiber)的话,可能就会改变这一点。

主流的操作系统都提供了线程实现,Java语言则提供了在不同硬件和操作系统平台下对线程操作的统一处理,每个已经调用过start()方法且还未结束的java.lang.Thread类的实例就代表着一个线程。我们注意到Thread类与大部分的Java类库API有着显著差别,它的所有关键方法都被声明为Native。在Java类库API中,一个Native方法往往就意味着这个方法没有使用或无法使用平台无关的手段来实现(当然也可能是为了执行效率而使用Native方法,不过通常最高效率的手段也就是平台相关的手段),接下来我们以一个通用的应用程序的角度来看看线程是如何实现的。

实现线程主要有三种方式:

  • 使用内核线程实现(1:1实现)
  • 使用用户线程实现(1:N实现)
  • 使用用户线程加轻量级进程混合实现(N:M实现)

1.内核线程实现

内核线程就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。每个内核线程可以视为内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核就称为多线程内核。

程序一般不会直接使用内核线程,而是使用内核线程的一种高级接口——轻量级进程,轻量级进程就是我们通常意义上所讲的线程,而每个轻量级进程都由一个内核线程支持,因此实现了用户线程和内核线程的绑定,这种轻量级进程与内核线程之间1:1的关系称为一对一的线程模型。

由于内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使其中某一个轻量级进程在系统调用中被阻塞了,也不会影响整个进程继续工作。轻量级进程也具有它的局限性:首先,由于是基于内核线程实现的,所以各种线程操作,如创建、析构及同步,都需要进行系统调用。而系统调用的代价相对较高,需要在用户态和内核态中来回切换。其次,每个轻量级进程都需要有一个内核线程的支持,因此轻量级进程要消耗一定的内核资源(如内核线程的栈空间),因此一个系统支持轻量级进程的数量是有限的。

2.用户线程实现

可以这样理解,用户线程指的是完全建立在用户空间的线程库上,系统内核不能感知到用户线程的存在及如何实现的。用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助。如果程序实现得当,这种线程不需要切换到内核态,因此操作可以是非常快速且低消耗的,也能够支持规模更大的线程数量,部分高性能数据库中的多线程就是由用户线程实现的。这种进程与用户线程之间1:N的关系称为一对多的线程模型。

用户线程的优势在于不需要系统内核支援,劣势也在于没有系统内核的支援,所有的线程操作都需要由用户程序自己去处理。线程的创建、销毁、切换和调度都是用户必须考虑的问题,而且由于操作系统只把处理器资源分配到进程,那诸如“阻塞如何处理”“多处理器系统中如何将线程映射到其他处理器上”这类问题解决起来将会异常困难,甚至有些是不可能实现的。因为使用用户线程实现的程序通常都比较复杂,除了有明确的需求外,一般的应用程序都不倾向使用用户线程。Java、Ruby等语言都曾经使用过用户线程,最终又都放弃了使用它。但是近年来许多新的、以高并发为卖点的编程语言又普遍支持了用户线程,譬如Golang、Erlang等,使得用户线程的使用率有所回升。

3.混合实现

线程除了依赖内核线程实现和完全由用户程序自己实现之外,还有一种将内核线程与用户线程一起使用的实现方式,被称为N:M实现。

在这种混合实现下,既存在用户线程,也存在轻量级进程。用户线程还是完全建立在用户空间中,因此用户线程的创建、切换、析构等操作依然廉价,并且可以支持大规模的用户线程并发。而操作系统支持的轻量级进程则作为用户线程和内核线程之间的桥梁,这样可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级进程来完成,这大大降低了整个进程被完全阻塞的风险。在这种混合模式中,用户线程与轻量级进程的数量比是不定的,是N:M的关系,这种就是多对多的线程模型。
许多UNIX系列的操作系统,如Solaris、HP-UX等都提供了M:N的线程模型实现。在这些操作系统上的应用也相对更容易应用M:N的线程模型。

Java线程是如何来实现的呢?

Java线程在早期的Classic虚拟机上(JDK 1.2以前),是基于一种被称为“绿色线程”(Green Threads)的用户线程实现的,但从JDK 1.3起,“主流”平台上的“主流”商用Java虚拟机的线程模型普遍都被替换为基于操作系统原生线程模型来实现,即采用1:1的线程模型。

操作系统支持怎样的线程模型,在很大程度上会影响上面的Java虚拟机的线程是怎样映射的,这一点在不同的平台上很难达成一致,因此《Java虚拟机规范》中才不去限定Java线程需要使用哪种线程模型来实现。线程模型只对线程的并发规模和操作成本产生影响,对Java程序的编码和运行过程来说,这些差异都是完全透明的。

Thread线程创建

线程两种创建方式解析

我们知道,在写代码时候经常用的创建线程的方式有两种:

  • 继承Thread
  • 实现Runnable

接下来我们先来看下上面两种创建方式的逻辑是怎样的,先看下应用中具体的代码写法

//Thread实现方式
class Student1 exten
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯巴达人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值