对象是过程的抽象,线程是调度的抽象。
一.并发的目的
并发是一种解耦策略,它把做什么(目的)和何时(时机)做分解开。
解耦目的与时机能明显地改进应用程序的吞吐量和结构。从结构的角度看,应用程序看起来更像许多台协同工作的计算机。
下面是有关并发的一些说法。
1.并发会在性能和编写额外代码上增加一些开销。
2.正确的并发是复杂的,对于简单的问题也是如此。
3.并发缺陷并非总能重现,所以常被看做偶发事件而忽略,未被当做真的缺陷看待。
4.并发常常需要对设计策略的根本性修改
二.并发防御原则
1.单一职责原则:分离并发相关代码与其他代码
2.限制数据作用域:数据封装,严格限制对可能被共享的数据的访问
3.线程应尽可能的独立:尝试将数据分解到可被独立线程(可能在不同的处理器上)操作的独立子集。
三.了解执行模型
限定资源:并发环境中有着固定尺寸或数量的资源,比如数据库连接和固定尺寸读/写缓存等。
互斥:每一时刻仅有一个线程能访问共享数据或共享资源
线程饥饿:一个活一组线程在很长时间内或永久被禁止。比如总是让执行的快的线程先运行,假如执行快的线程没完没了,则执行时间长的线程就会“挨饿”。
死锁:两个活多个线程互相等待执行结束。每个线程都有其他线程需要的资源,得不到其他线程拥有的资源,就无法终止。
活锁:执行次序一致的线程,每个都想要开始,但是其他线程已经“在路上”。由于竞步的原因,线程会持续尝试起步,但在很长时间内却无法如愿,甚至永远无法启动
四.警惕同步方法之间的依赖
避免使用一个共享对象的多个方法
五.保持同步区域微小
关键字synchronized制造了锁。
同一个锁维护的所有代码区域在任意时刻保证只有一个线程执行。
锁是昂贵的,因为它们带了了延迟和额外开销。
临界区应该被保护起来,尽可能少的设计临界区。临界区是为了确保程序正确而要阻止同时使用的代码区域。
将同步延展到最小临界区之外,会增加资源争用、降低执行效率。
所以尽可能减小同步区域。
六.很难编写正确的关闭代码
死锁是关闭经常遇到的问题。
假设生产者线程从父线程接收到关闭信号,然后迅速关闭。消费者线程可能还在等待生产线程发来消息,于是就被锁定在无法接收到关闭信号的状态中。它会死等生产者线程,永不结束从而导致父线程也无法结束。
所以尽早考虑关闭问题,尽早另其正常工作。
小结:
写好并发代码第一要诀就是遵循单一职责原则。线程相关代码应该保持短小和目的集中。
其次应该学习如何找到必须锁定的代码区域并加锁。不要锁定不必要的代码。避免从锁定区域中调用其他锁定区域。需要深刻理解某物hi否已共享。尽可能减少共享对象和共享范围。