先理解进程和线程有助于学习java并发编程。
进程的由来
为什么有进程:现在计算机的功能已经十分丰富了,可以一边看视频,一边浏览网页等等。但是在计算机开始出现的时候,计算机的功能十分简单,人们输入特定的指令,计算机就执行该指令,但是当人们休息或者思考的时候计算机就不工作,效率十分低下。
为了更好的利用计算机,人们把要执行的命令写下来,写在一个磁带上,让计算机去读取指令,然后执行指令,这样就提高了效率。这也就是批处理操作系统。
虽然这已经很优秀了,但还是有些问题,比如现在有两个任务A,B,A在执行的时候需要很多的IO操作,比如读取磁盘内容,而我们知道cpu很快,磁盘很慢,那么在读取磁盘的时候,cpu是空闲的。
解决办法:进程
在之前,内存中只有单独的一份数据,但是现在进程出现了,它要求内存中每一个程序都有一片属于自己的区域,每个区域互不干扰,而且保存了每个程序此时的状态,那么当A执行IO时,cpu空闲,此时cpu就可以执行B任务了。而且不止两个任务,还可以是多个,由于cpu的快速,使人们感觉多任务是在同时进行。
对于单核cpu来说,同一时刻只有一个进程占有cpu,至于那一个任务可以下一个占有cpu是不同的调度算法实现:比如先进先出,LRU,给予优先级,实现片轮转法等等。
线程的由来
进程仍然不能满足人们的需要,举个例子:在浏览器中,我们点击了下载按钮,那么此时浏览器的进程开始下载文件,如果此时cpu只是执行下载这个任务的话,显然我们就什么都干不了了。但是同时我们还想要浏览其他网页,还希望同时他开多个页面从服务端请求数据。
为了解决这个问题,线程出现了,线程可以说是轻量级进程(在linux中线程与进程区别很小),一个线程属于一个进程,一个进程可以有多个线程。也就是同一个进程下的线程是共享一片内存区域的,但是每个线程也有自己私有的数据比如程序计数器,调用栈等等。进程是资源分配的基本单位,线程是调度的基本单位。
当然同一时刻,一颗cpu依旧只能被一个线程占有,但是由于cpu强大的能力,看起来在一个进程中依旧是多任务执行的。
总体来说,进程的出现是为了提高计算机的利用率,线程的出现也是为了进一步提高计算机的利用率。
实际上再往下还有协程,go语言还有go程
java并发的问题
java作为一门强大的编程语言,也支持线程。
但是如果两个线程同时访问一个资源,而且这个资源只能同时被一个线程访问时,就需要进行同步问题。
比如:连个线程同时对一个文件进行写入,而没有先后顺序的话,那么这个文件就该删除了,因为没人能看得懂。
协程
进程与线程的调度都需要内核来完成,需要在用户态和内核态之间转换,因此效率较低。人们希望有可以不经过内核来完成调度,因此协程出现了。
协程的优势就是切换不需要经过内核,由用户控制,因此它更加轻量级。
但是对于单核CPU来说,同一时刻依旧只有一个协程用有CPU的使用权。
其他
并不是线程越多越好。
- 首先线程的切换是需要时间的,切换时需要保存此时线程执行的状态,然后载入将要执行的线程的状态
- 如果是cpu密集型,比如处理压缩视频,跑模型,需要大量的计算,那么没必要的线程切换反而会浪费cpu资源;如果是IO密集型,那么可以适当多增加线程,在响应IO是可以使用cpu干其他的事
- 选择是使用多进程还是多线程需要根据具体情况判断,譬如如果需要更快的响应速度,可以使用多线程;如果需要更加稳定可靠,对响应速度要求不高,可以使用多进程。