对并发/并行编程的总结

1. 并发和并行:一个好的并发算法未必是一个好的并行算法

2. 并发编程的2个设计要点:安全性能,在多CPU环境下还要考虑可扩展性

3. 安全性:

    a. 最常见的方法是要求对象在任意时刻都应该满足一致的状态(不变约束

    b. 在某些无阻塞算法中,允许对象暂时处于不一致状态,但是应该在运行中检测并立刻修正它

4. 影响安全的因素:原子性、可见性和指令顺序

5. 满足安全性的基本策略:

    a. 通过对象的不可变性保证对象总是满足不变约束:一个不变对象是线程安全的

        a. 无状态变量的对象,静态方法

        b. 所有状态变量均不可变的对象

        c. 可以尝试把原来可变的对象变成不可变对象(使用建立新实例再替换的方法)以减少同步的要求

        d. 实现不变对象要特别注意:在构造函数完全前,不能使用对象!危险在于构造函数中对this的泄漏(对象的逸出问题)

    b. 同步

        a. 锁

        b. 原子变量

        c. 其他工具类 (信号量,监视器)

        e. 防止死锁 (顺序化资源)

    d. 限制:限制对对象的并发访问

6. 提高扩展性的策略:

    关键在于减少串行代码:

    a. 减少锁的使用

        a. 是否可以允许过期数据?

            a. 

        a. 减少锁的范围,有可能阻塞的操作应该排除在锁的范围外,将共享变量的内容保存到本地变量,然后再锁的范围外操纵本地变量

        b. 分解锁

            对互相独立的共享变量,可以使用不同的锁(分拆锁);例子:对队列,可以使用2个锁分别锁定头尾

            使用读写锁来代替普通的锁;

            可以考虑用多个锁来代替一个大锁(分离锁),JDK1.5总的并发hashmap使用了16个锁来代替一个大锁以提高吞吐率,同样,在计算hashmap.size时,将分别计算各部分的size再汇总,以避免锁定整个对象

        c.  当在一个操作中需要同步多个共享变量时,为了减少同步多个变量带来的复杂性,可将多个变量放入一个单独的状态对象,然后使用新建并替换的方式减少甚至消除同步的要求

        d. 某些情况下可以用原子变量来代替锁

        e. 使用非阻塞算法来代替锁

        f. 遍历集合很难避免锁,但是可以考虑使用版本化迭代变量或者缓存的数据来减少锁的需要

        g. 考虑使用不变量/只读适配器(p98)

7. 线程协调和依赖

8. 管理线程

你可能感兴趣的:(编程)