P7架构师带你深刻了解线程的发展历史

P7架构师带你深刻了解线程的发展历史

 

专题简介

做为一个合格的Java程序员,必需要对并发编程有一个深层次的了解,在不少互联网企业都会重点考察这一块。可能不少工做3年以上的Java程序员对于这一领域几乎没有太多研究。因此在接下来内容中,我会将并发编程整个领域由浅到深作很是全面的分析。程序员

内容导航

  • 从操做系统的发展了解进程、线程模型
  • 线程的优点
  • 线程的生命周期
  • 线程的应用场景

1、了解进程、线程模型

每次学习一个新技术,我会先去了解这个技术的背景,这个过程看似浪费时间,其实在后续的学习过程当中,可以促进理解不少问题。因此对于线程这个概念,我会先从操做系统讲起。由于操做系统的发展带来了软件层面的变革。编程

从多线程的发展来看,能够操做系统的发展分为三个历史阶段:性能优化

  • 真空管和穿孔卡片
  • 晶体管和批处理系统
  • 集成电路和多道程序设计

最先的计算机只能解决简单的数学运算问题,好比正弦、余弦等。运行方式:程序员首先把程序写到纸上,而后穿孔成卡票,再把卡片盒带入到专门的输入室。输入室会有专门的操做员将卡片的程序输入到计算机上。计算机运行完当前的任务之后,把计算结果从打印机上进行输出,操做员再把打印出来的结果送入到输出室,程序员就能够从输出室取到结果。而后,操做员再继续从已经送入到输入室的卡片盒中读入另外一个任务重复上述的步骤。多线程

操做员在机房里面来回调度资源,形成计算机存在大量的空闲状态 。而当时的计算机是很是昂贵的,人们为了减小这种资源的浪费。就采用了 批处理系统来解决架构

批处理操做系统的运行方式:在输入室收集所有的做业,而后用一台比较便宜的计算机把它们读取到磁带上。而后把磁带输入到计算机,计算机经过读取磁带的指令来进行运算,最后把结果输出磁带上。批处理操做系统的好处在于,计算机会一直处于运算状态,合理的利用了计算机资源。(运行流程以下图所示)并发

 

P7架构师带你深刻了解线程的发展历史

 

(注:此图来源于现代操做系统)异步

批处理操做系统虽然可以解决计算机的空闲问题,可是当某一个做业由于等待磁盘或者其余I/O操做而暂停,那CPU就只能阻塞直到该I/O完成,对于CPU操做密集型的程序,I/O操做相对较少,所以浪费的时间也不多。可是对于I/O操做较多的场景来讲,CPU的资源是属于严重浪费的。分布式

多道程序设计的出现解决了这个问题,就是把内存分为几个部分,每个部分放不一样的程序。当一个程序须要等待I/O操做完成时。那么CPU能够切换执行内存中的另一个程序。若是内存中能够同时存放足够多的程序,那CPU的利用率能够接近100%。微服务

在这个时候,引入了第一个概念- 进程, 进程的本质是一个正在执行的程序,程序运行时系统会建立一个进程,而且给每一个进程分配独立的内存地址空间保证每一个进程地址不会相互干扰。同时,在CPU对进程作时间片的切换时,保证进程切换过程当中仍然要从进程切换以前运行的位置出开始执行。因此进程一般还会包括程序计数器、堆栈指针。高并发

有了进程之后,可让操做系统从宏观层面实现多应用并发。而并发的实现是经过CPU时间片不端切换执行的。对于单核CPU来讲,在任意一个时刻只会有一个进程在被CPU调度

有了进程之后,为何还会出现线程呢?

在一个应用进程中,会存在多个同时执行的任务,若是其中一个任务被阻塞,将会引发不依赖该任务的任务也被阻塞。举个具体的例子来讲,咱们日常用word文档编辑内容的时候,都会有一个自动保存的功能,这个功能的做用是,当计算机出现故障的状况下若是用户未保存文档,则可以恢复到上一次自动保存的点。假设word的自动保存由于磁盘问题致使写入较慢,势必会影响到用户的文档编辑功能,直到磁盘写入完成用户才可编辑,这种体验是不好的。若是咱们把一个进程中的多个任务经过线程的方式进行隔离,那么按照前面提到的进程演进的理论来讲,在单核心CPU架构中能够经过CPU的时间片切换实现线程的调度充分利用CPU资源以达到最大的性能。

咱们用了比较长的篇幅介绍了进程、线程发展的历史。总的来讲是人们对于计算机的要求愈来愈高;对于计算机自己的资源的利用率也在不断提升。

2、线程的优点

前面分析了线程的发展历史,这里简单总结一下线程有的优点以下

  • 线程能够认为是轻量级的进程,因此线程的建立、销毁要比进程更快
  • 从性能上考虑,若是进程中存在大量的I/O处理,经过多线程可以加快应用程序的执行速度(经过CPU时间片的快速切换)。
  • 因为线程是CPU的最小调度单元,因此在多CPU架构中可以实现真正的并行执行。每个CPU能够调度一个线程

这里有两个概念不少人没有搞明白,就是并行和并发

并行:同时执行多个任务,在多核心CPU架构中,一个CPU核心运行一个线程,那么4核心CPU,能够同时执行4个线程

并发:同处理多个任务的能力,一般咱们会经过TPS或者QPS来表示某某系统支持的并发数是多少。

总的来讲,并行是并发的子集。也就是说咱们能够写一个拥有多线程并行的程序,若是在没有多核心CPU来执行这些线程,那就不能以并行的方式来运行程序中的多个线程。因此并发程序能够是并行的,也能够不是。Erlang之父Joe Armstrong经过一张图型的方式来解释并发和并行的区别,图片以下

 

P7架构师带你深刻了解线程的发展历史

 

3、线程的生命周期

线程是存在生命周期的,从线程的建立到销毁,可能会经历6种不一样的状态,可是在一个时刻线程只能处于其中一种状态

  • NEW:初始状态,线程被建立时候的状态,尚未调用start方法
  • RUNNABLE:运行状态,运行状态包含就绪和运行两种状态,由于线程启动之后,并非当即执行,而是须要经过调度去分配CPU时间片
  • BLOCKED:阻塞状态,当线程去访问一个加锁的方法时,若是已经有其余线程得到锁,那么当前线程会处于阻塞状态
  • WAITING:等待状态,设置线程进入等待状态等待其余线程作一些特定的动做进行触发
  • TIME_WAITING:超时等待状态,和WAITING状态的区别在于超时之后自动返回
  • TERMINATED:终止状态,线程执行完毕

下图整理了线程的状态变动过程及变动的操做,每个具体的操做原理,我会在后续的文章中进行详细分析。

 

P7架构师带你深刻了解线程的发展历史

 

 

这里有一个问题你们可能搞不明白,BLOCKED和WAITING这两个阻塞有什么区别?

  • BLOCKED状态是指当前线程在等待一个获取锁的操做时的状态。
  • WAITING是经过Object.wait或者Thread.join、LockSupport.park等操做实现的
  • BLOCKED是被动的标记,而WAITING是主动操做
  • 若是说得再深刻一点,处于WAITING状态的线程,被唤醒之后,须要进入同步队列去竞争锁操做,而在同步队列中,若是已经有其余线程持有锁,则线程会处于BLOCKED状态。因此能够说BLOCKED状态是处于WAITING状态的线程从新唤醒的必经的状态

4、线程的应用场景

线程的出现,在多核心CPU架构下实现了真正意义上的并行执行。也就是说,一个进程内多个任务能够经过多线程并行执行来提升程序运行的性能。那线程的使用场景有哪些呢?

  • 执行后台任务,在不少场景中,可能会有一些定时的批量任务,好比定时发送短信、定时生成批量文件。在这些场景中能够经过多线程的来执行
  • 异步处理,好比在用户注册成功之后给用户发送优惠券或者短信,能够经过异步的方式来执行,一方面提高主程序的执行性能;另外一方面能够解耦核心功能,防止非核心功能对核心功能形成影响
  • 分布式处理,好比fork/join,将一个任务拆分红多个子任务分别执行
  • BIO模型中的线程任务分发,也是一种比较常见的使用场景,一个请求对应一个线程

合理的利用多线程,能够提高程序的吞吐量。同时,还能够经过增长CPU的核心数来提高程序的性能,这就体现了伸缩性的特色

推荐一个交流学习交流圈子:142019080 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

相关文章
相关标签/搜索