01线程概述

1. 线程由来

进程和线程并非从计算机诞生就存在,随着计算机硬件的发展,操作系统经历了从单进程、多进程、多线程,才逐渐发展为现在的并发模型。

1.1 单进程操作系统

早期的计算机都是单核计算机,即CPU中只有一个内核。
进程:现代操作系统在运行一个程序时,会为其创建一个进程。进程是对运行时程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发。
一个内核同时只能运行一个程序。,所以可以实现进程并发,无法实现进程并行。
单进程操作系统:一次只能执行一个程序,当一个程序执行完成之后,才会轮到下一个程序来执行。每个程序在执行的过程中,都独占计算机资源(比如CPU、内存)。
单核计算机只能实现单进程操作系统,无法实现多进程操作系统。

1.2 多进程操作系统

对于多核计算机来说,CPU中包括多个内核。正是多核技术造就了多进程操作系统。
对于单核计算机来说,无法实现并行,只能在一个处理器上通过交替运行多个进程来实现进程并发。
对于多核计算机来说,既能将多个进程同时运行在多个处理器上来实现进程并行,又能在同一个处理器上交替运行多个进程来实现进程并发。

进程并发进程并行
单核计算机(单进程操作系统)可以不可以
多核计算机(多进程操作系统)可以可以

操作系统用进程表Process Table来记录所有进程的执行信息。进程表中每一个表项叫做进程控制块,简称PCB(Process Control Block)。一个PCB记录一个进程的执行信息。PCB包含的信息具体如下所示:

  • 进程ID:每个进程会有一个ID
  • 进程状态:NEW、READY、RUNNING、WAITING、TERMINATED等
  • 程序计数器(Program Counter),也叫做PC计数器,用来记录接下来要执行的代码所在的内存地址。
  • 寄存器值:CPU在执行过程中,会用到各种寄存器来暂存计算结果,因此,在暂停进程时,操作系统需要将当下各个寄存器的值保存在PCB中,以便恢复执行时恢复寄存器的值。
  • 调度信息:比如进程的优先级等。
  • 文件列表:记录已经打开的文件的信息,比如读取到哪个文件的哪个位置了。
  • 其他信息,比如统计信息,进程运行了多长时间等
    寄存器在CPU执行程序的过程中起到重要的作用。操作系统将执行进程从进程A切换到进程B时,会将当前寄存器的值保存到进程A的PCB中,然后,拿进程B的PCB中保存的寄存器值重设寄存器。

1.3 多线程操作系统

实际上,多进程已经很好地满足了多个程序并发执行的需求。但是,对于同一个程序中的多个任务,无法并行或并发执行,只能串行执行。
进程是操作系统为正在运行的程序提供的抽象。
进程由程序运行过程中所涉及到的资源构成,包括:数据(比如创建的对象、变量)、代码、资源(比如打开的文件)、执行信息(代码的执行情况)。
而线程
在一个进程里可以创建多个线程,多个线程共享代码段、数据段、以及打开的文件等资源,每个线程都有自己独立的栈(函数调用栈)、程序计数器、寄存器值。进程管理共享资源,每个线程管理自己的独立资源。
有了线程之后,操作系统调度的最小单元就从进程转化为了线程。

1.3.1 设计

在设计方面,引入线程之后,进程只负责线程共享资源的管理(比如虚拟内存中的代码段、数据段,以及打开的文件等),而线程负责代码的执行。原来由进程负责的部分数据现在由线程负责,比如栈(函数调用栈)、程序计数器、寄存器值。
在引入线程前,操作系统按照进程来分配CPU执行时间。在引入线程后,操作系统按照线程来分配CPU执行时间。因此进程切换替换为了线程切换。

1.3.2 性能

多进程支持多个程序之间的并行,多线程支持单个程序内部多个任务之间的并行。
在性能方面,随着多核计算机的发展,多线程可以让一个程序并行运行在多个CPU上,程序执行的效率更高。
程序中的逻辑可以粗略分为两类:需要CPU参与执行的逻辑和不需要CPU参与执行的逻辑(比如读写IO)。实际上,提高程序执行效率(主要是吞吐量)的关键,是让两类逻辑并行执行,也就是在IO读写的同时,CPU也在执行指令。
如果操作系统只支持多进程,那么只是两个程序之间有可能并行执行,程序内部包含的两类逻辑之间并不能并行执行。在引入多线程之后,程序内也可以并行执行。也就是说,多进程相当于粗粒度的并行,多线程相当于细粒度的并行。

1.3.3 易用性

引入多线程之后,每个线程负责执行一个逻辑,多个逻辑之间的调度执行,由操作系统来完成。如果没有多线程,多个逻辑之间的调度执行,需要程序员自己去维护。引入多线程降低了程序的开发难度。
Java虚拟机除了要执行应用程序的代码之外,还需要做JIT编译、垃圾回收等任务。这些任务与业务逻辑之间相互独立,更适合在独立的线程中完成。
为什么要使用多线程
多任务:多任务是操作系统的一种能力,看起来可以在同一时刻运行多个程序。并发执行的进程数目并不受限于CPU的数目。操作系统会为每个进程分配CPU时间片,给人并行处理的感觉。
多线程:多线程程序在更低一层扩展了多任务的概念,使得单个程序看起来在同时完成多个任务。每个任务在一个线程中执行,线程是控制线程的简称。如果一个程序可以同时运行多个线程,则称这个程序是多线程的。
多进程与多线程的区别:本质区别在于每个进程都拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之间的通信比进程之间的通信更加简单;与进程相比,线程更轻量级,创建、撤销一个线程比启动新进程的开销要小得多。
多线程的应用场景:一个浏览器可以同时下载几幅图片;一个Web服务器需要同时服务并发的请求;图形用户界面程序用一个独立的线程从宿主操作环境收集用户界面事件。

进程并发进程并行线程并发线程并行
单核计算机(单进程操作系统)可以不可以--
多核计算机(多进程操作系统)可以可以--
多核计算机(多线程操作系统)可以可以可以可以

2. 线程调度策略

对于支持多线程的操作系统,多个线程共同竞争CPU资源,那么操作系统必须设计一定的算法,来调度多个线程轮流执行。
基础的调度算法有很多,比如先来先服务、最短作业优先、高优先级优先、多优先级队列、轮转调度等。
大部分操作系统都会用到轮转调度这种基础的调度算法,在此基础上再组合其他的基础调度算法,以实现兼顾公平性、优先级、响应时间、吞吐量等。
轮转调度算法:将所有状态为READY的线程放到一个队列中,操作系统每次从队首取一个线程,分配时间片执行此线程,当时间片用完之后,将这个线程暂停,放入队列的尾部,然后从队首再取新的线程继续执行。除了时间片用完之外,其他情况也会导致线程切换,比如线程等待IO读写完成、线程等待获取锁,以及线程主动让出时间片。
因为操作系统的调度算法比较复杂,所以时间片的大小一般并不是简单固定的。不过,时间片的大小一般处于10ms~100ms之间,不能太大也不能太小。时间片太大的话会导致其他线程等待的时间过长,时间片太小的话会导致线程上下文切换过于频繁。
**频繁的线程上下文切换会导致程序执行缓慢。**切换过程不仅包含了上下文切换,还有线程调度算法的执行,而且线程切换还会导致缓存失效。
操作系统一般会保证在一个固定的时间间隔内,所有的就绪线程都要运行一遍,这样才能保证每个线程都不会等待太久。也就是说,如果线程数较多,那么时间片就相对短一些,如果线程数较少,那么时间片就相对长一些。所以,对于CPU密集型的程序来说,程序中创建过多的线程会导致程序变慢,原因就是线程多导致时间片变短,上下文切换耗时增加。
频繁加锁和释放锁也会导致程序变慢。一个原因是加锁和释放锁本身的耗时;另一个是加锁会导致其他线程请求锁时会被阻塞,在没有用完时间片的情况下,就切换为其他线程执行。执行代码逻辑的时间减少,大部分时间都浪费在了上下文切换上。
实际上,在线程没有发明之前,进程还担任着线程执行代码的作用,当时的进程调度算法和刚刚讲的线程调度算法基本一致。当线程发明之后,进程只负责资源的管理,线程承担了大部分进程的工作。所以,线程在发明之处也叫做子进程,或者轻量级进程。

3. 线程状态

在线程调度执行的过程中,线程会处于不同的状态,比如有时候在执行,有时候在等待操作系统调度,有时候在等待I/O读写完成,有时候在等待获取锁等等。为了方便标明线程所处的状态,操作系统一般会定义如下线程状态:
(1)NEW:新创建的线程,在没有调用start()函数之前,线程处于NEW状态;
(2)READY:线程一切就绪,等待操作系统调度;
(3)RUNNING:线程正在执行;
(4)WAITING:线程在等待I/O读写完成、等待获取锁、等待时钟定时到期(调用sleep()函数)等等。总之,等待其他事件发生之后,线程才能被调度使用CPU,此时线程的状态就是WAITING;
(5)TERMINATED:线程终止状态。线程终止之后,未必就立即销毁。有些操作系统为了节省线程创建的时间,会复用处于TERMINATED状态的线程。
不同的操作系统可能会定义不同的线程状态,不过基本上不会相差很大。与操作系统定义的线程状态相比,Java语言定义的线程状态略有不同,可以参考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值