与串行程序开发相比,并发编程的难度更大,编写、调试、维护都很困难,导致很多开发人员图省事放弃并发编程。但是现在已经进入了多核移动互联时代,现在连入门级的手机都是多核的,所以如何充分发挥多核处理器系统的强大的计算能力,是我们每个开发人员需要面对的。
一、并发的历史
1.串行时代
串行执行的特点
每次只能运行一个程序,只有其执行完成其他程序才能开始执行。
这种方式人类流水线的工作方式,其优势在于直观性和简单性。
串行执行的缺点
资源利用率低,单个程序执行不能有效率用cpu资源,尤其是其进行长时间IO操作的情况下。
缺乏公平性,不同用户和计算机不能同等的使用计算机资源。
缺乏灵活性,一个复杂的业务系统需要完成多个大的任务,往往需要垂直切分为多个业务系统更好实现。
2.进程时代
我们发现生活中人们总是可以在串行和异步之间进行并行权衡达到优雅高效做事。例如人们往往在煮粥的同时,可以摘菜、洗菜、切菜,待菜准备好的时候,可能粥也就煮好了,这时候正好可以炒菜。
所以为了解决串行编程的缺点,操作系统出现了。
进程执行的特点
可以同时执行多个程序,但是每个程序在单独的进行中执行。
每个进程分配单独的资源,例如内存、文件句柄等。
不同进程之间可以通过套接字、信号量等进行交换数据。
3.线程时代
线程执行的特点
线程共享父进程内的资源,例如内存句柄、文件句柄等,需要同步共享数据的访问,防止发生不可预测的结果。
每个线程都有自己的程序计数器、堆栈、局部变量等。
现代操作系统以线程为基本调度单位,线程可以不同的cpu上进行调度执行。
二、线程的优势
1.充分利用多(核)处理器的计算能力。
随着移动设备的普及,多核设备随处可见,多线程程序可以提高处理器的资源利用率。
即使多线程在单处理器上也可以通过异步提高IO密集型操作的性能。
2.建模简单
一个程序往往会包含很多不同类型的任务,很多时候往往可以为不同的任务分配不同的线程进行处理。比如在ASP.NET中,每个请求都是由某个线程处理的,同时GC在另外的线程上负责垃圾回收。
3.简化异步处理
web服务器接受客户端请求,如果为每个链接分配线程并使用同步IO,这样会严重降低并发能力。
单线程是很难实现异步IO的,通过多线程可以很方便的实现同时处理大量的IO请求。
4.UI界面响应更友好
UI界面往往在单独的线程中执行,代码逻辑在另外的线程中运行。
三、多线程的风险
1.安全性问题
由于线程执行顺序的不可预测性,如果没有进行充足同步的情况下,往往会由于对共享数据的无序操作,导致不可预知的结果。比如对共享数据value的访问,可能会导致多个线程获取到相同的value。
2.活跃性问题
活跃性问题往往是为了保证数据的安全性问题,对线程的执行顺序加以限制,从而导致活跃性的问题,比如死锁、饥饿、活锁等。
3.性能问题
活跃性问题会导致性能问题;
多线程需要运行时开销,例如上下文切换、数据同步机制导致缓存失效和编译器优化失效。