并发编程:并发概念和基础
介绍
当我们烧水的时候我们往往不是在旁边等着它烧开,而是在它烧开之前我们也许会做些其它的事情比如看书、看会儿电视,
一旦水烧开了我们就去处理烧开的水(比如泡茶)。这也体现出我们做事的效率,计算机也是如此。
当计算机在进行磁盘IO或网络IO时,由于比较耗时,CPU此时是出于空闲状态的,这无疑是对CPU的一种浪费没有充分利用CPU资源。
所以通常都是当进行磁盘IO或网络IO等比较耗时的操作时,CPU任然会执行其它需要计算的任务。
比如从磁盘读文件并处理文件的流程
5 seconds reading file A
2 seconds processing file A
5 seconds reading file B
2 seconds processing file B
如果是单线程处理的话,那么总共需要14秒才能处理完
如果是采用多线程处理那么当A文件读完之后,继续读B文件的同时另一个线程可以开始处理A文件了,那么处理完AB只需要12秒。
多线程和并发
在单核CPU的计算机上,微观层面上永远只有一个线程在执行,但是随着计算机硬件的发展,
现在很多计算机都是运行在多核CPU上,因此想要充分利用CPU资源的话,使用多线程无疑是一种很好的方式。
进程
进程是操作系统调度的重要和基础单元,特点就是操作系统给进程划分一块独立的内存空间。
进程之间通常是不会共享内存的,彼此协同比较困难。
线程
线程是操作系统调度最小单元,线程共享其所属进程的内存空间,正因此共享内存模型,使得进程下的线程协同比较容易实现。
多线程的优势
1、充分发挥多处理器的处理能力
2、某些场景下建模更加简单(尤其是web场景下请求响应模型,典型如Servlet实现)
3、异步事件的简化处理
4、响应更灵敏的用户界面
多线程带来的挑战
1、安全性问题
2、编程复杂度
串行与并行
串行:单线程场景下应用程序的运行就是串行的,其运行方式符合人们的思维,做完一件事情之后再做一件事情,依次执行
并行:同时执行多个任务,并行更多时候指的是任务的并行而非线程的并行。
并发:指的是多线程场景下对共享资源的争夺运行
备注:我理解的是并行与并发最核心区别在于,并行是同时运行(通常是任务),并发是没有同时运行的
(这里同时运行指的是对共享资源的操作没有同时操作)
不恰当的例子:
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
并发必然是发生在多线程场景下,单线程并不存在并发问题。
并发产生条件
1、多线程场景
2、存在资源共享(局部变量是线程私有的,成员变量则会被线程共享)
3、共享资源是有状态的(所谓有状态的意思简单理解就是其变化对程序和业务逻辑会产生影响)
Java与多线程
Java自启动就是运行在多线程下的,GC是一个线程(守护线程),main方法也是一个线程(主线程)
并发两板斧
并发编程最容易遇到的问题就是就是安全问题,因此解决方式有两种
1、使用同步方法或同步代码块(Synchronized关键字)
2、使用锁机制(ReentranLock)
备注:
同步方法和同步代码块是基于JVM实现的,相对比较粗粒度优点就是简单粗暴不容易出错,但是性能也不是很好。
锁机制是一种显示锁,能够实现更细粒度的控制。风险就是需要自己控制锁的释放,否则容易引发死锁。
参考
1、http://tutorials.jenkov.com/java-concurrency/benefits.html
2、并发编程实战