多线程的优点
1. 资源利用率更好
CPU能够在等待IO的时候做一些其他的事情
2. 程序设计在某些情况下更简单
在单线程应用程序中,编写程序手动处理读取和处理的顺序,必须记录每个文件读取和处理的状态。相反,你可以启动两个线程,每个线程处理一个文件的读取和操作。线程会在等待磁盘读取文件的过程中被阻塞。在等待的时候,其他的线程能够使用CPU去处理已经读取完的文件。
其结果就是,磁盘总是在繁忙地读取不同的文件到内存中。这会带来磁盘和CPU利用率的提升。而且每个线程只需要记录一个文件,因此这种方式也很容易编程实现
3. 程序响应更快
设想一个服务器应用,它在某一个端口监听进来的请求,当一个请求到来时,它去处理这个请求,然后再返回去监听
例:while(server is active){
listenfor request
Processrequest
}
如果一个请求需要占用大量的时间来处理,在这段时间内新的客户端就无法发送请求给服务端。只有服务器在监听的时候,请求才能被接收。另一种设计是,监听线程把请求传递给工作者线程(worker thread),然后立刻返回去监听。而工作者线程则能够处理这个请求并发送一个回复给客户端。
例:while(server is active){
listen forrequest
Hand request toworker thread
}
这种方式,服务端线程迅速地返回去监听。因此,更多的客户端能够发送请求给服务端。这个服务也变得响应更快
多线程的缺点
1. 设计更复杂
在多线程访问共享数据时,这部分代码需要特别的注意,线程之间的交互往往非常复杂,不正确的线程同步产生的错误难以被发现与重现修复
2. 上下文切换开销大
当CPU从执行一个线程切换到执行另一个线程时,它会先存储当前线程的本地数据、程序指针等,然后载入另一个线程的本地数据、程序指针等,最后才开始执行
维基百科关于上线文切换相关内容:http://en.wikipedia.org/wiki/Context_switch
3. 增加资源消耗
线程在运行时需要从计算机中得到一些资源,除了CPU线程还需要一些内存来维持它本地的堆栈
并发编程模型
1. 并行工作者
该模型中,委派者将传入的作业分配给不同的工作者,每个工作者完成整个任务,工作者们并行运作在不同的线程上,设置可能在不同的CPU上
例:汽车厂中每个工人将拿到汽车的生产规格,并独立从头到尾完成所有工作
在Java应用系统中,并行工作者模型是最常见的并发模型
1) 并行工作者模型的优点
容易理解,只需添加更多的工作者来提供系统的并行速度
2) 并行工作者模型的缺点
1. 共享状态可能会很复杂
线程需要以某种方式存取共享数据,以确保某个线程的修改能够对其他线程可见(数据修改需要同步到主存中,不仅仅将数据保存在执行这个线程的CPU的缓存中)。线程需要避免竟态,死锁以及很多其他共享状态的并发性问题
2. 无状态的工作者
共享状态能够被系统中其他线程修改,所以工作者在每次需要的时候必须重读状态,以确保每次都能访问到最新的副本,不管共享状态是保存在内存中还是在外部数据库中,工作者无法在内部保存这个状态称为无状态的
每次都重读需要的数据,将会导致速度变慢,特别是状态保存在外部数据库中的时候
3. 任务顺序是不确定的
作业执行顺序是不确定的。无法保证哪个作业最先或者最后被执行。
例:作业A可能在作业B之前就被分配工作者了,但是作业B反而有可能在作业A之前执行。
并行工作者模式的这种非确定性的特性,使得很难在任何特定的时间点推断系统的状态。这也使得它也更难保证一个作业在其他作业之前被执行
2. 流水线模型
每个工作者只负责作业中的部分工作。当完成了自己的这部分工作时工作者会将作业转发给下一个工作者。每个工作者在自己的线程中运行,并且不会和其他工作者共享状态。有时也被成为无共享并行模型
通常使用非阻塞的IO来设计使用流水线并发模型的系统。非阻塞IO意味着,一旦某个工作者开始一个IO操作的时候(比如读取文件或从网络连接中读取数据),这个工作者不会一直等待IO操作的结束。IO操作速度很慢,所以等待IO操作结束很浪费CPU时间。此时CPU可以做一些其他事情。当IO操作完成的时候,IO操作的结果(比如读出的数据或者数据写完的状态)被传递给下一个工作者。
有了非阻塞IO,就可以使用IO操作确定工作者之间的边界。工作者会尽可能多运行直到遇到并启动一个IO操作。然后交出作业的控制权。当IO操作完成的时候,在流水线上的下一个工作者继续进行操作,直到它也遇到并启动一个IO操作。
反应器,事件驱动系统
采用流水线并发模型的系统有时候也称为反应器系统或事件驱动系统
比较流行的反应器/事件驱动平台
Vert.x
AKKa
Node.JS(JavaScript)
Actor和Channel是两种比较类似的流水线模型
在Actor模型中每个工作者被称为actor。Actor之间可以直接异步地发送和处理消息。Actor可以被用来实现一个或多个像前文描述的那样的作业处理流水线。
而在Channel模型中,工作者之间不直接进行通信。相反,它们在不同的通道中发布自己的消息(事件)。其他工作者们可以在这些通道上监听消息,发送者无需知道谁在监听。
1) 流水线模型的优点
1. 无须共享的状态
工作者之间无共享状态,意味着实现的时候不用考虑所有因并发访问共享对象而产生的并发性问题,在实现工作者的时候就好像是单个线程在处理工作-基本上是一个单线程的实现。
2. 有状态的工作者
他们可以在内存中保存他们需要操作的数据,只需要在最后将更改写回到外部存储系统,因此,有状态的工作者通常比无状态的工作者具有更高的性能
3. 较好的硬件整合
单线程代码在整合底层硬件的时候往往具有更好的优势。首先,当能确定代码只在单线程模式下执行的时候,通常能够创建更优化的数据结构和算法
4. 合理的作业顺序
基于流水线并发模型实现的并发系统,在某种程度上是有可能保证作业的顺序的。作业的有序性使得它更容易地推出系统在某个特定时间点的状态
2) 流水线模型的缺点
流水线并发模型最大的缺点是作业的执行往往分布到多个工作者上,并因此分布到项目中的多个类上。这样导致在追踪某个作业到底被什么代码执行时变得困难
3. 函数式并行模型
理解不深
信息内容来自:http://ifeve.com/java-concurrency-thread-directory/
本人仅整理相应内容让读者更容易理解