死磕java线程系列之线程模型

     2022-04-01     478

关键词:

问题

(1)线程有哪些类型?

(2)线程模型有哪些?

(3)各语言是怎么实现自己的线程模型的?

简介

在Java中,我们平时所说的并发编程、多线程、共享资源等概念都是与线程相关的,这里所说的线程实际上应该叫作“用户线程”,而对应到操作系统,还有另外一种线程叫作“内核线程”。

用户线程位于内核之上,它的管理无需内核支持;而内核线程由操作系统来直接支持与管理。几乎所有的现代操作系统,包括 Windows、Linux、Mac OS X 和 Solaris,都支持内核线程。

最终,用户线程和内核线程之间必然存在某种关系,本章我们一起来学习下建立这种关系常见的三种方法:多对一模型、一对一模型和多对多模型。

多对一模型

技术图片

多对一线程模型,又叫作用户级线程模型,即多个用户线程对应到同一个内核线程上,线程的创建、调度、同步的所有细节全部由进程的用户空间线程库来处理。

优点:

  • 用户线程的很多操作对内核来说都是透明的,不需要用户态和内核态的频繁切换,使线程的创建、调度、同步等非常快;

缺点:

  • 由于多个用户线程对应到同一个内核线程,如果其中一个用户线程阻塞,那么该其他用户线程也无法执行;

  • 内核并不知道用户态有哪些线程,无法像内核线程一样实现较完整的调度、优先级等;

许多语言实现的协程库基本上都属于这种方式,比如python的gevent。

一对一模型

技术图片

一对一模型,又叫作内核级线程模型,即一个用户线程对应一个内核线程,内核负责每个线程的调度,可以调度到其他处理器上面。

优点:

  • 实现简单,本文由公从号“彤哥读源码”原创;

缺点:

  • 对用户线程的大部分操作都会映射到内核线程上,引起用户态和内核态的频繁切换;

  • 内核为每个线程都映射调度实体,如果系统出现大量线程,会对系统性能有影响;

Java使用的就是一对一线程模型,所以在Java中启一个线程要谨慎。

多对多模型

技术图片

多对多模型,又叫作两级线程模型,它是博采众长之后的产物,充分吸收前两种线程模型的优点且尽量规避它们的缺点。

在此模型下,用户线程与内核线程是多对多(m : n,通常m>=n)的映射模型。

首先,区别于多对一模型,多对多模型中的一个进程可以与多个内核线程关联,于是进程内的多个用户线程可以绑定不同的内核线程,这点和一对一模型相似;

其次,又区别于一对一模型,它的进程里的所有用户线程并不与内核线程一一绑定,而是可以动态绑定内核线程, 当某个内核线程因为其绑定的用户线程的阻塞操作被内核调度让出CPU时,其关联的进程中其余用户线程可以重新与其他内核线程绑定运行。

所以,多对多模型既不是多对一模型那种完全靠自己调度的也不是一对一模型完全靠操作系统调度的,而是中间态(自身调度与系统调度协同工作),因为这种模型的高度复杂性,操作系统内核开发者一般不会使用,所以更多时候是作为第三方库的形式出现。

优点:

  • 兼具多对一模型的轻量;

  • 由于对应了多个内核线程,则一个用户线程阻塞时,其他用户线程仍然可以执行;

  • 由于对应了多个内核线程,则可以实现较完整的调度、优先级等;

缺点:

  • 实现复杂,本文由公从号“彤哥读源码”原创;

Go语言中的goroutine调度器就是采用的这种实现方案,在Go语言中一个进程可以启动成千上万个goroutine,这也是其出道以来就自带“高并发”光环的重要原因。

后面讲到Java中的ForkJoinPool的时候,我们会拿Go语言的PMG线程模型来对比讲解。

总结

(1)线程分为用户线程和内核线程;

(2)线程模型有多对一模型、一对一模型、多对多模型;

(3)操作系统一般只实现到一对一模型;

(4)Java使用的是一对一线程模型,所以它的一个线程对应于一个内核线程,调度完全交给操作系统来处理;

(5)Go语言使用的是多对多线程模型,这也是其高并发的原因,它的线程模型与Java中的ForkJoinPool非常类似;

(6)python的gevent使用的是多对一线程模型;

彩蛋

你所学过的语言都是使用的什么线程模型呢?

死磕java线程系列之创建线程的8种方式

问题(1)创建线程有哪几种方式?(2)它们分别有什么运用场景?简介创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有8种创建线程的方式,你知道吗?继承Thread类并重写run()方法publicclassCreatingThread01extendsThr... 查看详情

死磕java线程系列之线程的生命周期

(手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于java8版本。简介大家都知道线程是有生命周期,但是彤哥可以认真负责地告诉你网上几乎没有一篇文章讲得是完全正确的。常见的错误有:就绪状态、运行中状... 查看详情

死磕java线程系列之线程池深入解析——体系结构

(手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于java8版本。简介Java的线程池是块硬骨头,对线程池的源码做深入研究不仅能提高对Java整个并发编程的理解,也能提高自己在面试中的表现,增加被录取的可能... 查看详情

死磕java线程系列之线程池深入解析——构造方法

(手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于java8版本。简介ThreadPoolExecutor的构造方法是创建线程池的入口,虽然比较简单,但是信息量很大,由此也能引发一系列的问题,同样地,这也是面试中经常被问... 查看详情

死磕java线程系列之线程池深入解析——生命周期

(手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于java8版本。注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类。简介上一章我们一起重温了下线程的生命周期(六种状态还记得不?),但是你知不知道其... 查看详情

死磕java线程系列之自己动手写一个线程池(代码片段)

欢迎关注我的公众号“彤哥读源码”,查看更多源码系列文章,与彤哥一起畅游源码的海洋。(手机横屏看源码更方便)问题(1)自己动手写一个线程池需要考虑哪些因素?(2)自己动手写的线程池如何测试?简介线程池是Java... 查看详情

死磕java线程系列之自己动手写一个线程池(代码片段)

(手机横屏看源码更方便)问题(1)自己动手写一个线程池需要考虑哪些因素?(2)自己动手写的线程池如何测试?简介线程池是Java并发编程中经常使用到的技术,那么自己如何动手写一个线程池呢?本文彤哥将手把手带你写... 查看详情

死磕java线程系列之线程池深入解析——定时任务执行流程

(手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于java8版本。注:本文基于ScheduledThreadPoolExecutor定时线程池类。简介前面我们一起学习了普通任务、未来任务的执行流程,今天我们再来学习一种新的任务——定... 查看详情

死磕java线程系列之自己动手写一个线程池(续)(代码片段)

(手机横屏看源码更方便)问题(1)自己动手写的线程池如何支持带返回值的任务呢?(2)如果任务执行的过程中抛出异常了该怎么处理呢?简介上一章我们自己动手写了一个线程池,但是它是不支持带返回值的任务的,那么... 查看详情

死磕java线程系列之自己动手写一个线程池(续)(代码片段)

(手机横屏看源码更方便)问题(1)自己动手写的线程池如何支持带返回值的任务呢?(2)如果任务执行的过程中抛出异常了该怎么处理呢?简介上一章我们自己动手写了一个线程池,但是它是不支持带返回值的任务的,那么... 查看详情

死磕java同步系列之volatile解析(代码片段)

问题(1)volatile是如何保证可见性的?(2)volatile是如何禁止重排序的?(3)volatile的实现原理?(4)volatile的缺陷?简介volatile可以说是Java虚拟机提供的最轻量级的同步机制了,但是它并不容易被正确地理解,以至于很多人不... 查看详情

死磕java同步系列之reentrantreadwritelock源码解析(代码片段)

问题(1)读写锁是什么?(2)读写锁具有哪些特性?(3)ReentrantReadWriteLock是怎么实现读写锁的?(4)如何使用ReentrantReadWriteLock实现高效安全的TreeMap?简介读写锁是一种特殊的锁,它把对共享资源的访问分为读访问和写访问... 查看详情

死磕java同步系列之开篇

简介同步系列,这是彤哥想了好久的名字,本来是准备写锁相关的内容,但是java中的CountDownLatch、Semaphore、CyclicBarrier这些类又不属于锁,它们和锁又有很多共同点,都是为了协同多线程的执行,都是一种同步器,所以这里就借... 查看详情

死磕java同步系列之mysql分布式锁

问题(1)什么是分布式锁?(2)为什么需要分布式锁?(3)mysql如何实现分布式锁?(4)mysql分布式锁的优点和缺点?简介随着并发量的不断增加,单机的服务迟早要向多节点或者微服务进化,这时候原来单机模式下使用的sync... 查看详情

死磕java同步系列之终结篇

欢×××”,查看更多源码系列文章,与彤哥一起畅游源码的海洋。(手机横屏看源码更方便)简介同步系列到此就结束了,本篇文章对同步系列做一个总结。脑图下面是关于同步系列的一份脑图,列举了主要的知识点和问题点,... 查看详情

死磕java同步系列之phaser源码解析

问题(1)Phaser是什么?(2)Phaser具有哪些特性?(3)Phaser相对于CyclicBarrier和CountDownLatch的优势?简介Phaser,翻译为阶段,它适用于这样一种场景,一个大任务可以分为多个阶段完成,且每个阶段的任务可以多个线程并发执行,... 查看详情

死磕java并发-----死磕java并发精品合集(代码片段)

...xff1a;https://www.cmsblogs.com/category/1391296887813967872『chenssy』【死磕Java并发】系列是LZ在2017年写的第一个死磕系列,一直没有做一个合集,这篇博客则是将整个系列做一个概览。先来一个总览图:【高清图,请关注“Jav... 查看详情

死磕java同步系列之jmm(javamemorymodel)(代码片段)

简介Java内存模型是在硬件内存模型上的更高层的抽象,它屏蔽了各种硬件和操作系统访问的差异性,保证了Java程序在各种平台下对内存的访问都能达到一致的效果。硬件内存模型在正式讲解Java的内存模型之前,我们有必要先了... 查看详情