老早以前的计算机只有一个处理器,而一个处理器在同一时刻只能处理一条指令,换句话说,咱们的代码须要一行一行的按顺序被计算机执行,计算机只能把一个程序完整的执行完,而后再执行第二个程序。因此计算机专业的同窗们要排队去机房作实验,一我的执行完然他的程序后,第二我的再执行本身的程序,这也就意味着全部计算机资源是被一个程序独占的,计算机资源包括处理器、内存、硬盘、输入/输出设备啥的。这样的计算机系统咱们称之为裸机
。java
后来人们发现对于价格高昂的计算机设备来讲,在换人的过程当中就浪费了好多时间,时间就是金钱,有这些时间能够多执行好多程序了。因此有人写了一个程序,把全部同窗们须要作实验的程序都放在这个程序里排个队,由这个程序来协调各个同窗们的程序执行,一个执行完了当即换成另外一个,这样就不用人工干预了,因此他们把这样的系统叫作简单批处理系统
,而那个负责协调各个童鞋们程序的程序,就是所谓的操做系统
的雏形。sql
咱们知道,处理器的速度是嗖嗖的,比内存访问的速度快好多个数量级,而内存又比硬盘、打印机等I/O
设备啥的快好多个数量级,而程序执行过程当中又免不了从硬盘里读个文件,往打印机输出个啥的,因此处理器浪费了好多时间等待这些I/O操做的完成。再一次,时间就是金钱,为了尽量的剥削计算机的运算能力,在程序遇到I/O
操做或者什么其余会阻塞程序执行的操做时,处理器会转向执行其它的程序,何时这个阻塞的操做完成了,再掉过头继续执行它。从宏观上看,处理器能够各个程序轮流执行,因此这样的系统就称为多道批处理系统
。编程
有的同窗对排队执行程序这个事儿颇有意见,你们都是学生,凭啥先执行你的后执行个人,你要是写了个while(true)
,那你们都得玩儿完~因此人们给每一个程序都分配一点处理器时间去轮流执行,每一个程序分配到的执行时间就叫作时间片
,这个过程也叫作分时处理
。又由于处理器速度太快了,时间片
的大小能够作到微秒毫秒的大小,因此这个切换的过程对于人来讲根本感受不出来,因此看起来像各个程序在同时执行。不事后来人们在一台计算机上又装了多个处理器,就是咱们常据说的4核
、8核
啥的,因此也可能真正的在同时执行。windows
而时间片
具体设置为多大,处理器怎么切换各个程序的执行,这些工做就是所谓的操做系统
来控制的。微信
咱们本身写的程序,也就是所谓的用户程序
是由操做系统来管理的,人们把一个执行着的程序叫作一个进程
(英文名:Process
),每一个进程
都有这么两个特色:架构
程序在运行过程当中须要必定的资源,好比内存、I/O
啥的,这些东西不能在不一样进程间共享,假如一个进程占了另外一个进程的内存,那另外一个进程的数据不就丢失了么;一个进程正在使用打印机输出东西,另外一个进程也使用的话,不就尴尬了么。因此进程所拥有的这些资源是不能共享的,而这种资源分配的活是由操做系统
来管理的。并发
操做系统
会为它管理的进程分配时间片
,来调度哪一个进程应该被处理器处理,哪一个应该先休息一下子。分布式
因此咱们如今电脑里每一个运行着的程序都是一个进程,能够打开你的任务管理器(windows
)或者活动监视器(mac
),看到咱们的电脑里其实有好多好多进程喔,什么QQ、微信、音乐播放器、视频播放器啥的。高并发
在操做系统级别上,进程根据它运行的状况,能够分红下边5种状态:源码分析
新建
刚刚建立的那个时刻,操做系统
会为这个进程在内存中建立相应的数据,好比分配这个进程的ID,优先级什么的~这个状态持续的时间比较短。
就绪
一旦该进程相关的一些数据建立好了,这个进程就会被放在一个叫就绪队列
的队列里,以后操做系统就会从这个队列里挑一个进程放处处理器里执行。
运行
这个进程被操做系统
分配了时间片,处理器开始执行它。
阻塞
在执行进程的过程当中,可能遇到某些阻塞的动做,好比I/O
操做,处理器若是一直等待该阻塞动做完成的话就太浪费时间了,因此会把等待阻塞动做完成的进程放到一个叫阻塞队列
的队列里,以后并不会从这个队列里挑选即将执行的进程,而是直到该阻塞动做完成,才从新把该进程放到就绪队列
里等待执行。
退出
该进程执行完毕,或者遇到了什么错误,或者操做系统就是想弄死它,它就被杀死了,这个状态里操做系统可能还会记录一下死因啥的,这个过程也很短。
这些状态的具体转换过程看下图:
到目前为止,咱们的编程模式都是串行编程
,也就是处理器执行完一条指令再执行另外一条。举个例子啊,好比你妈给你布置了两个任务
:一是去打瓶酱油,二是去烧一壶水,按照串行编程
的方式就是两个任务依次进行,也就是说你先打酱油,而后回来再烧水。这么作没啥问题,可是没有效率啊,因此你也能够先把水烧上,而后去打酱油,回来正好水烧开了~这种多个任务同时进行的编程方式就叫作并行编程
。
回到计算机中来,串行编程
的方式就是咱们把全部要完成的任务放到一个进程
中去执行,而并行编程
的方式就是咱们去开几个进程
同时执行(注:这个同时
多是假的,若是只有单个处理器,那就是看上去是同时
的)。这种并行编程
的优点是显而易见的:
现代计算机的处理器愈来愈多,不用白不用。若是全部的任务都塞到1个进程中,而计算机实际有100个处理器,那么将会有99%的计算能力将被浪费。
即便是在单个处理器中,为多个任务建立多个进程也是有好处的。先执行的任务可能会须要执行某些I/O
操做而形成阻塞,因此就须要等待I/O
操做完成才能继续执行。可是若是为每一个任务建立一个进程以后,一个任务阻塞掉并不会影响别的任务的正常执行。
把一个大任务拆分红若干个小任务天然是会事情清晰许多(注:也不是绝对啊),也就是所谓的大事化小,小事化了~因此把各个任务分配到不一样进程里去执行在咱们编程方面也会容易一些(注:不是绝对啊)。
进程
是个好东西,能够给每一个任务都分配一个进程以达到并发执行的目的。但是运行了一段时间人们发现仍是有一些很差的地方的:
这个对于为了一个大目标细分红的若干小任务很不友好。比方说对于一个网站来讲,针对每个访问网站的链接都去建立一个进程,若是咱们想累加一下总的访问链接数就比较麻烦了,由于各个进程不能去修改同一块内存。
建立、切换、销毁进程成本太大。
小贴士: 因为咱们的主题是java语言里的并发操做,至于操做系统底层对于建立、切换、销毁进程都要作哪些东西不是咱们唠叨的范围,可是这些操做的开销真的很大,你知道这一点就行了~
再返回头来看进程
的两个特色,一是对资源的全部权,二是能够做为操做系统调度和执行的单位,这两个特色是没有关系的,也就是说独立的,现代的好多操做系统已经把这两个特色给拆开了,能够被调度和执行的单位一般被称做线程
或者轻量级进程
,而拥有资源全部权的单位一般被称为进程
。
小贴士: 因为历史缘由,原先的进程
既是资源的分配单位,也是调度和执行的单位,因此咱们打开一个程序就至关于打开一个进程。 提出线程
概念以后,这种打开一个程序就至关于打开一个进程
的叫法也被保留了下来。其实如今打开一个程序的意思是打开一个进程而且打开若干个于这个进程相关联的线程
。
看一下这个线程
的各类特色
操做系统每开始执行一个程序,都会为其分配所需的资源以及建立若干个程序执行流
,也就是说会建立一个线程以及若干线程。
线程
能够共享同一个进程中的各类资源由于线程
是从属于某个进程,因此进程中的内存、I/O
啥的资源这个线程
均可以访问到。接着上边那个例子,咱们能够对于每个连到网站的链接均可以分配一个线程,而后在申请一起内存表示链接数,每建立一个线程都把链接数加1,问题就愉快的解决了。
由于只是一个调度和执行的单位,原本就是原先进程概念的一部分,因此建立、切换、销毁线程的成本就小多了。
线程通讯比进程通讯的效率高
原先进程间通讯须要配合各类机制,如今线程间因为能够共享内存,因此通讯就easy多了。
小贴士: 至于进程间须要啥机制我这就不说了,不是咱们讨论的范围。
因此线程
的提出完美的解决了一开始提出的把不一样任务分配给不一样进程执行的缺陷,如今咱们能够把不一样的任务分配给不一样的线程
去执行,不只能够方便通讯交流,并且建立和使用的成本还低~
因为线程只是单纯的继承了线程中调度和执行的特性,因此原先进程拥有的状态,如今线程同样拥有,也就是:建立
、就绪
、执行
、阻塞
、退出
。
本文的重点是你有没有收获与成长,其他的都不重要,但愿读者们能谨记这一点。同时我通过多年的收藏目前也算收集到了一套完整的学习资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、Jvm性能调优、Spring,MyBatis,Nginx源码分析,Redis,ActiveMQ、、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点高级进阶干货,但愿对想成为架构师的朋友有必定的参考和帮助