计算机cpu工作原理,操作系统调度单核cpu时其实是在不停的切换任务,因为cpu同一时间只能做一件事,而且cpu做事速度很快,往往在完成一件任务时需要等待其他零件完成任务(比如硬盘读写i/o阻塞),此时为了最大限度的理由资源,cpu只能在不同任务间来回切换,就是我们所说的并发了。
但并发带来了一些问题,原先单任务现在变成了多个任务,任务之间的切换怎么进行,这时候就引入了进程的概念。
用进程来对应一个程序,每个进程对应一定的内存地址空间,并且只能使用它自己的内存空间,各个进程间互不干扰。并且进程保存了程序每个时刻的运行状态,这样就为进程切换提供了可能。
当进程暂时时,它会保存当前进程的状态(比如进程标识、进程的使用的资源等),在下一次重新切换回来时,便根据之前保存的状态进行恢复,然后继续执行。这就是并发,能够让操作系统从宏观上看起来同一个时间段有多个任务在执行。
换句话说,进程让操作系统的并发成为了可能。
而线程是进程的子集,线程也是一个应用程序最小的执行单元。
进程的出现解决了操作系统的并发问题,但是对于一个进程来说,它内部也需要执行多个子任务,比如读取,计算,实时显示,为了更大限度的提升效率,人们引入了线程的概念。进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能。
注意,一个进程虽然包括多个线程,但是这些线程是共同享有进程占有的资源和地址空间的。进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。
线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;
调度和切换:线程上下文切换比进程上下文切换要快得多
生活中的举例:你在上网时,挂着QQ,看着爱奇艺,并用迅雷下载着文件。这时候QQ,爱奇艺,迅雷就可以认为是一个个进程。而你在QQ中可以和张三、李四等人同时聊天,那么张三、李四等人的聊天界面就是一个个线程。
问题:是否多线程的性能一定就由于单线程呢?
不一定,要看具体的任务以及计算机的配置。比如说:对于单核CPU,如果是CPU密集型任务,如解压文件,多线程的性能反而不如单线程性能,
因为解压文件需要一直占用CPU资源,如果采用多线程,线程切换导致的开销反而会让性能下降。但是对于比如交互类型的任务,肯定是需要使用多线程的、而对于多核CPU,对于解压文件来说,多线程肯定优于单线程,因为多个线程能够更加充分利用每个核的资源。
虽然多线程能够提升程序性能,但是相对于单线程来说,它的编程要复杂地多,要考虑线程安全问题。
因此,在实际编程过程中,要根据实际情况具体选择。
线程作为程序执行的最小单位,他有着一个完整的生命周期:
如上图,线程的生命周期大体分为如下5个部分:
NEW(新建) , RUNNABLE(可运行) , RUNING (运行), BLOCKED(阻塞) , TERMINATED(消亡)
下面对每个状态进行具体讲解
NEW 状态
当我们创建一个线程对象,如 new Thread() 后,此时线程还没开始调用start方法启动,那么这时候的线程就处于NEW 状态。其实跟确切的说,此时线程还不存在,在没调用start() 方法前,你只是用关键字 new 创建了一个普通的Java对象。
NEW 状态可以通过start() 进入 RUNNABLE状态。
RUNNABLE 状态
线程对象创建后要想变成RUNNABLE 状态必须调用 start()方法,调用该方法后,才能算是真正的在 JVM进程中创建了一个线程。但线程一旦启动并不会马上就能得到执行,线程的运行与否与进程一样是取决于CPU的调度的,我们就把这种等待执行的状态称之 RUNNABLE(可运行)状态,表示它具备了执行资格,但是还没能真正的执行起来。
由于此时线程并不是Running状态,所以该状态下的线程不会直接进入 BLOCKED 和 TERMINATED状态,即使在线程的执行中调用了wait、sleep或者其他block的IO操作等,也必须是线程获得了CPU的调度执行权才可以转变状态。
RUNNABLE的线程只能意外终止 或者进入RUNNING状态。
RUNNING状态
当CPU通过轮询或者其他方式从任务可执行队列中选中了线程,此时它才能真正的执行自己的内部逻辑代码,而此时线程的状态就是RUNING状态。可以说 一个正在RUNNING 状态的线程事实上也是RUNNABLE 的,但是反过来说则不成立。
RUNNING状态下的线程状态常见转换:
RUNNING 变成 BLOCK 状态
1.调用了sleep、wait方法而进入了waitSet中。
2.进行某个阻塞的IO操作,比如网络数据的读写
3.为获取某个锁资源,从而加入到该锁的阻塞队列中
RUNNING 变成 RUNNABLE 状态
1.CPU调度器轮询使该线程放弃了执行
2.线程主动调用了yield方法,放弃了CPU的执行权
RUNNING 变成 TERMINATED 状态
1.调用stop方法
BLOCKED 状态
线程由于某些原因进入了阻塞状态,详见上文,线程在BLOCKED状态可进行的状态切换:
进入 RUNNABLE状态
1.线程完成了指定时间的休眠
2.线程阻塞的操作结束,比如读取到了想获取的数据
3.Wait中的线程被其他线程 notify/notifyall唤醒
4.线程获取到了某个锁资源
5.线程在阻塞过程中被打断,比如其他线程调用了interrupt方法
进入 TERMINATED 状态
调用stop或者意外死亡(JVM Crash)
TERMINATED状态
线程的最终状态,该状态的线程不会在进行状态变换,意味着整个生命周期都结束了。线程进入到TERMINATED状态的情况:
1.线程运行正常结束,结束生命周期
2.线程运行出错意外结束
3.JVM Crash,导致所有线程都结束
了解线程的生命周期各状态之间的转换非常重要,每种语言具体定义的状态枚举也许不同,单总体来说都会在这5种状态的范畴之内。
原文:https://www.cnblogs.com/jiusixiantan/p/14037891.html