阅读《java并发编程实战》4.1.1章 收集同步需求时,
反复出现了“不变性条件”,“不可变条件”,“后验条件”,令我一头雾水

原版说话

  • preconditions 前置条件
  • post‐conditions 后置条件
  • invariants 不变性条件

通过国外论坛stactoverflow,我找到了答案

1.preconditions

preconditions,pre-conditions都是同一个意思,前置条件。书中翻译为先验条件,有的地方还翻译成前验条件,不需要太纠结术语。
在调用该方法之前条件必须为true

2.post‐conditions

post‐conditions,postconditions,表示后置条件,后验条件
在方法顺利完成之后条件必须为true

3.invariants

invariants 表示不变性条件,不可变条件,不变式。java内存模型和java虚拟机规范都没有给出正式定义。
书中也讲的很含糊,
在2.1 什么是线程安全性章节中给出了invariants的作用
在良好的规范中通常会定义各种不变性条件(Invariant)来约束对象的状态,以及定义各种后验条件(Postcondition)来描述对象操作的结果。

先看看国外程序员怎么说的:What is an invariant?

An invariant is more “conceptual” than a variable. In general, it’s a property of the program state that is always true. A function or method that ensures that the invariant holds is said to maintain the invariant.

一个不变性条件比一个变量更“概念化”,一般而言,它(invariant)是程序状态的一个属性(变量)而且它总是true(作为布尔类型)。函数或方法 确保不变性条件保持被称为 维护不变性。

For instance, a binary search tree might have the invariant that for every node, the key of the node’s left child is less than the node’s own key. A correctly written insertion function for this tree will maintain that invariant.

例如,二叉搜索树可能具有每个节点的不变性条件,左子节点的key总是小于own节点的key。为这棵树正确编写插入函数将维护它的不变性。(这个数据结构我没用过)

As you can tell, that’s not the sort of thing you can store in a variable: it’s more a statement about the program. By figuring out what sort of invariants your program should maintain, then reviewing your code to make sure that it actually maintains those invariants, you can avoid logical errors in your code.

你可以看出,这不是那种可以存储在变量中的东西:它更多是关于程序的一条语句。通过弄清楚你的程序应该维护什么样的不变性条件,然后检查代码以确保它确实维护了这些不变性条件,这样就可以避免代码中的逻辑错误。

简单的案例1

public class Calc {private int value = 0;private boolean isValid() {return value >= 0;}public void add(int val) {// precondition:前置条件,只有该条件为true,才能执行我们的业务逻辑if (!isValid()) {throw new IllegalStateException();}//实际逻辑代码value += val;// postcondition:后置条件,一般用于判断状态迁移是否是有效的if (!isValid()) {throw new IllegalStateException();}}
}

案例2:
书中给了个例子

后置条件用来判断刚才的++操作是否执行成功。假如 Counter的value值为 17 ,在++后,Counter的value值只能是 18 。如果不是18,说明在++过程中,value被改过。当下一个状态需要依赖当前状态时,这个操作就必须是一个复合操作。所以++操作要和后置条件的验证操作必须是复合操作(可以保证原子性)。
如果不是复合操作会怎样?那么即使当前的value值是18,当value值也有可能被改过。某个线程把value改到19,趁你没反应过来时,又把值改回了18。虽然最终值都是18,但不意味着期间没有问题。

案例3

重新看看书中2.3章的例子

2.3 加锁机制
当在 Servlet 中添加一个状态变量时,可以通过线程安全的对象来管理 Servlet 的状态以维护 Servlet 的线程安全性。但如果想在 Servlet 中添加更多的状态,那么是否只需添加更多的线程安全状态变量就足够了?

假设我们希望提升 Servlet 的性能:将最近的计算结果缓存起来,当两个连续的请求对相同的数值进行因数分解时,可以直接使用上一次的计算结果,而无须重新计算(这并非一种有效的缓存策略, 5.6 节将给出一种更好的策略。)要实现该缓存策略,需要保存两个状态:最近执行因数分解的数值,以及分解结果。

我们曾通过 AtomicLong 以线程安全的方式来管理计数器的状态,那么,在这里是否可以使用类似的 AtomicReference① 来管理最近执行因数分解的数值及其分解结果吗?

①AtomicLong 是一种替代 long 类型整数的线程安全类,类似地, AtomicReference 是一种替代对象引用的线程安全类。在第 15 章将介绍各种原子变量( Atomic Variable )及其优势。

在程序清单 2-5 中的 UnsafeCachingFactorizer 实现了这种思想。

程序清单 2-5 该 Servlet 在没有足够原子性保证的情况下对其最近计算结果进行缓存(不要这么做)

@NotThreadSafe
public class UnsafeCachingFactorizer implements Servlet {private final AtomicReference<BigInteger> lastNumber= new AtomicReference<BigInteger>();private final AtomicReference<BigInteger[]> lastFactors= new AtomicReference<BigInteger[]>();public void service(ServletRequest req, ServletResponse resp) {BigInteger i = extractFromRequest(req);if (i.equals(lastNumber.get()))encodeIntoResponse(resp, lastFactors.get());else {BigInteger[] factors = factor(i);lastNumber.set(i);lastFactors.set(factors);encodeIntoResponse(resp, factors);}}
}

然而,这种方法并不正确。尽管这些原子引用本身都是线程安全的,但在 UnsafeCachingFactorizer 中存在着竞态条件,这可能产生错误的结果。

在线程安全性的定义中要求,多个线程之间的操作无论采用何种执行时序或交替方式,都要保证不变性条件不被破坏。
UnsafeCachingFactorizer 的不变性条件之一是:在 lastFactors 中缓存的因数之积应该等于在 lastNumber 中缓存的数值。只有确保了这个不变性条件不被破坏,上面的 Servlet 才是正确的。当在不变性条件中涉及多个变量时,各个变量之间并不是彼此独立的,而是某个变量的值会对其他变量的值产生约束。因此,当更新某一个变量时,需要在同一个原子操作中对其他变量同时进行更新。

在某些执行时序中, UnsafeCachingFactorizer 可能会破坏这个不变性条件。在使用原子引用的情况下,尽管对 set 方法的每次调用都是原子的,但仍然无法同时更新 lastNumber 和 lastFactors 。如果只修改了其中一个变量,那么在这两次修改操作之间,其他线程将发现不变性条件被破坏了。同样,我们也不能保证会同时获取两个值:在线程 A 获取这两个值的过程中, 线程B可能修改了它们,这样线程 A 也会发现不变性条件被破坏了。

要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量

总结:毕竟是国外写的书,按字面翻译还是很难理解的,还是得举点例子

前置条件,不变性条件,后置条件 --《java并发编程实战》相关推荐

  1. 《Java 并发编程实战》--读书笔记

    Java 并发编程实战 注: 极客时间<Java 并发编程实战>–读书笔记 GitHub:https://github.com/ByrsH/Reading-notes/blob/maste ...

  2. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  3. java并发编程实战学习(3)--基础构建模块

    转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put ...

  4. java单线程共享,「Java并发编程实战」之对象的共享

    前言 本系列博客是对<Java并发编程实战>的一点总结,本篇主要讲解以下几个内容,内容会比较枯燥.可能大家看标题不能能直观的感受出到底什么意思,这就是专业术语,哈哈,解释下,术语(term ...

  5. 【极客时间】《Java并发编程实战》学习笔记

    目录: 开篇词 | 你为什么需要学习并发编程? 内容来源:开篇词 | 你为什么需要学习并发编程?-极客时间 例如,Java 里 synchronized.wait()/notify() 相关的知识很琐 ...

  6. Java并发编程实战之互斥锁

    文章目录 Java并发编程实战之互斥锁 如何解决原子性问题? 锁模型 Java synchronized 关键字 Java synchronized 关键字 只能解决原子性问题? 如何正确使用Java ...

  7. aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  8. JAVA并发编程实战——共享对象

    目录 思维导图 1. 可见性 1. 1 过期数据 1.2 锁和可见性 1.3 Volatile变量 2. 发布和逸出 2.1 安全构建实践 3. 线程封闭 3.1 栈限制 3.2 ThreadLoca ...

  9. Java并发编程实战————恢复中断

    中断是一种协作机制,一个线程不能强制其他线程停止正在执行的操作而去执行其他操作. 什么是中断状态? 线程类有一个描述自身是否被中断了的boolean类型的状态,可以通过调用 .isInterrupte ...

最新文章

  1. Transformers 研究指南
  2. C#函数式编程之可选值
  3. webstorm遇到的问题
  4. JSP中使用iframe导致内层网页CSS失效问题的解决方案
  5. 20w7珠led驱动电源电路图_LED驱动电源:用TL431做的几个恒流电路分享!
  6. 报告:5G 网络切片可能会给不法分子留下漏洞!
  7. matlab时域转复频域,信号与系统实验(MATLAB版)实验15连续系统的复频域分析.ppt...
  8. 计算机应用技术知识,计算机应用技术主要学什么
  9. iOS中,在类的源文件(.m)中,@interface部分的作用?
  10. python magic_method
  11. Android开发的四大组件
  12. 【Python】Python中的日志级别
  13. [渝粤教育] 陕西科技大学 食品营养安全与健康 参考 资料
  14. python读取大智慧数据_大智慧数据格式
  15. 计算机能直接和cpu交换数据的是,内存储器_能直接与CPU交换信息的存储器是
  16. c语言中sprint的用法
  17. Java中的按拼音排序
  18. 由ERA5逐小时数据获取逐日数据——三种方法
  19. 转载:虚拟机安装centos6.5出现 unsupported hardware detected 解决方法
  20. 51单片机ADDA数模转换

热门文章

  1. 苹果手机很卡怎么解决_iPhone很卡怎么办,教您如何解决iPhone很卡问题!
  2. 背包三讲(感谢崔添翼 (Tianyi Cui)大佬的无私奉献)
  3. 你选择了你的记忆,和生活。
  4. 计算器的改良(NOIP2000)
  5. 【博弈论】bzoj1022[SHOI2008]小约翰的游戏John
  6. Axure预览样式错误混乱
  7. 计算机域名的解释,通俗易懂:域名与IP的关系讲解
  8. linux pcs 所有命令,BaiduPCS-Go Windows或linux下百度网盘cmd命令行详细使用方法
  9. 【2629】Identity Card 【比较坑 / 水题】
  10. 关于《算法的乐趣》历法一章演示程序错误的说明