编写正确的程序很难,而编写正确的并发程序则难上加难。
采用并发的原因
1. 资源利用率:在等待外部操作(如I/O操作)执行完成前,同时运行其他程序,以提高资源利用率
2. 公平性:对不同用户和程序来说,计算机资源的的使用权应该是平等的,一种高效的运行模式是通过粗粒度的时间分片共享计算机资源
2.1 关于粗细粒度:粗粒度和细粒度的区别主要是出于重用的目的,像类的设计,为尽可能重用,所以采用细粒度的设计模式,将一个复杂的类(粗粒度)拆分成高度重用的职责清晰的类(细粒度).对于数据库的设计,原责:尽量减少表的数量与表与表之间的连接,能够设计成一个表的情况就不需要细分,所以可考虑使用粗粒度的设计方式。
2.2 关于时间分片:时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间,线程调度并不受到Java虚拟机控制。
2.3 关于线程调度器:线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦创建一个线程并启动它,它的执行便依赖于线程调度器的实现。
3. 便利性:通常在计算多个任务时,应该编写多个程序,每个程序执行一个任务并在必要时相互通信,这比一个程序计算所有任务要更容易实现。
线程的优势
1. 发挥多处理器的强大能力。
2. 建模的简单性:可以将复杂且异步的的工作分解为一组简单且同步的工作流,每个工作流在单独的线程中运行,并在特定的同步位置进行交互。
3. 异步事件的简化处理:异步较为复杂,实现难度比线程大,很容易出错。
4. 响应用户界面的灵敏度高。
补充:
并行
一般指并行计算,是说同一时刻有多条指令同时被执行,这些指令可能执行于同一CPU的多核上,或者多个CPU上,或者多个物理主机甚至多个网络中。
异步
与同步相对应,异步指的是让CPU暂时搁置当前请求的响应,处理下一个请求,当通过轮询或其他方式得到回调通知后,开始运行。多线程将异步操作放入另一线程中运行,通过轮询或回调方法得到完成通知,但是完成端口,由操作系统接管异步操作的调度,通过硬件中断,在完成时触发回调方法,此方式不需要占用额外线程。
线程的风险
1. 安全性问题
1.1 在没有充足同步的情况下,多个线程的操作执行顺序是不可预测的。
1.2 由于多个线程要共享相同的内存地址,并且是并发运行,因此它们可能会访问或修改其他线程正在使用的变量,导致非串行性的问题。
2. 活跃性问题:当某个操作无法继续执行下去的时,就会发生活跃性问题(形式之一是造成无限循环),包括死锁、饥饿、活锁。
3. 性能问题:线程调度器临时挂起活跃线程并转而执行另一个线程时,会出现频繁的上下文切换,带来极大地开销;当线程共享数据时,必须使用同步机制,这往往会抑制某些编译器的优化。