2线程安全性

2018-04-25  本文已影响0人  WFitz

编写线程安全代码的关键

Java中的同步机制

  1. synchronized
  2. volatile变量
  3. 显式锁(Explicit Lock)
  4. 原子变量

如何将共享的可变的状态变量的访问变为安全的

  1. 不在线程间共享该状态变量
  2. 将状态变量修改为不可变的变量
  3. 在访问状态变量时使用同步机制

有利于设计线程安全类的条件

  1. 良好的面向对象技术
  2. 不可修改性
  3. 明晰的不变性规范

编写并发程序的原则

如何理解线程安全

什么是线程安全的类

无状态对象一定是线程安全的

竞态条件

  1. 定义
    • 在并发编程中,多个线程由与不恰当的执行读写共享数据的顺序而导致出现不正确的结果的情况,就叫做竞态条件(Race Condition)
    • 维基百科:竞争冒险(race hazard)又名竞态条件、竞争条件(race condition),它旨在描述一个系统或者进程的输出依赖于不受控制的事件出现顺序或者出现时机
    • 换句话说就是正确的结果取决于运气
  2. 最常见的竞态条件类型:
    • 先检查后执行(Check-Then-Act),即通过一个可能失效的观测结果来决定下一步动作
    • 自增操作(count++),该操作包括三个步骤:读取count,计算count+1,给count赋值
  3. 大多数竞态条件的本质:基于一种可能失效的观测结果来作出判断或执行某个计算
  4. 如何避免静态条件:要避免静态条件问题,就必须在某个线程修改该变量时,通过某种方式防止其他线程使用这个变量,从而确保其他线程只能在修改完成之前或之后读取和修改状态,而不是在修改状态的过程中(即保证类似“先检查后执行”、“读取-修改-写入”这样的复合操作是原子的)

可重入

  1. Java的线程是可重入的
  2. 概念:已经获取锁的线程再次进入该锁保护的代码块时不需要从新获取锁
  3. 粒度:“重入”意味着获取锁的操作的粒度是“线程”,而不是“调用”
  4. 一种实现:为每个锁关联一个获取计数值和一个所有者线程。当计数值为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将记下锁的持有者,并且将获取计数值置为1.如果同一个线程再次获取这个锁,计数值将递增,而当线程退出同步代码块时,计数器会相应的递减。当计数值为0时,这个锁将被释放

用锁来保护状态

  1. 对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁
  2. 对于每个包含多个状态变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护

安全性-活跃性-性能

经验

  1. 通常,在简单性和性能之间存在着相互制约的因素。当实现某个同步策略时,一定不要盲目地为了性能而牺牲简单性(这可能会破坏安全性)
  2. 当执行时间较长的计算或者可能无法快速完成的操作时(例如,网络I/O或控制台I/O),一定不要持有锁
上一篇下一篇

猜你喜欢

热点阅读