多线程设计模式

TODO

Single Threaded Execution 模式

同一时间内只能让一个线程执行处理。

synchronized标记方法。

STE模式下存在一个共享资源类,包含 safeMethod 和 unsafeMethod ,并会保护不安全的方法。

何时使用STE

  • 多线程访问:共享资源类的实例可能被多个线程同时访问时。

  • 共享资源类实例的状态可能发生变化时。

  • 需要确保安全性时。(Java集合类大多为非线程安全)

STE分析

生存性

死锁危险,此时:

  • 存在多个共享资源角色

  • 线程在持有某个共享资源角色的锁时,获取其他角色的锁

  • 获取共享资源角色的锁顺序不固定

可复用性

多线程下的继承,如果共享资源类子类存在 unsafeMethod ,则会影响父类的安全性。(继承反常)

临界区及性能

临界区:只允许单个线程执行的程序。

STE模式会降低性能,原因:

  • 获取锁需要处理时间

  • 线程冲突导致等待

细节和习题

  • 使unlock不被return和异常处理打断。

  • 注意选对获取锁的实例

  • 引用类型、int、char等基本类型的赋值和引用操作是原子的,而long、double类型的赋值和引用是非原子操作。

Immutable 模式

示例类

  • 只含get方法不含set方法的类

    如果getter的实现不常规,如返回StringBuffer,则外部可能修改实例内容。

  • 类字段声明为private final

当使用需频繁访问的共享实例时,Immutable模式下的类不需要使用synchronized进行保护,性能较高。

StringBuffer类和String类是成对的mutable和immutable类,前者可随便改写字符串(为确保安全,需妥善使用synchronized),后者不可改写,但引用的速度更快。二者通过构造函数,可互相转换。

final关键字

  • 无法创建final类的子类(无法拓展)

  • final实例方法不会被子类的方法重写;静态final方法表示不会被子类的方法隐藏。

  • final字段只可被赋值一次

    对final实例字段:声明时或构造函数中赋值

    对final静态字段:声明时或静态初始化代码块中赋值

集合类与多线程

Collections.synchronizedList

ArrayList是线程不安全的类,改进如下:

final List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());

进行“写”,无需多加处理;对于“读”,需要额外同步:

copy-on-write

java.util.concurrent.CopyOnWriteArrayList类使用“写时复制”机制,确保安全的数组被整体复制,无需担心迭代器依次读取元素时元素被修改。

习题


参考: 《图解Java多线程设计模式》

最后更新于

这有帮助吗?