前言

下面简单总结学习Java并发的笔记,关于如何利用面向对象思想写好并发程序的建议。面向对象的思想和并发编程属于两个领域,但是在Java中这两个领域却可以融合到一起。在Java语言中,面向对象编程的思想能够让并发编程变得更加简单。下面将从封装共享变量、识别共享变量间的约束条件和制定并发访问策略三方面介绍如何使用面向对象思想去指导编写并发程序。

封装共享变量

在并发编程中,格外关心的一个重点便是多线程对共享变量的访问问题。我们需要控制好对共享变量的访问接口。面向对象就有一个非常好的特性:封装(将属性和实现细节封装在对象内部),外界只能通过目标对象提供的公共方法来间接访问这些内部属性。使用面向对象的这个特性,就可以非常轻松地掌控共享变量的访问路径。

利用面向对象思想编写并发程序的思路:将共享变量作为对象属性封装在内部,对所有公共方法定制并发访问策略

例如,下面的计数器程序。计数器程序共享变量只有一个,即value,我们把它作为Counter类的属性,并且将两个公共方法get()set()声明为同步方法,这样Counter类就成为了一个线程安全的类了。

public class Counter {
private long value;
synchronized long get(){
return value;
}
synchronized long addOne(){
return ++value;
}
}

识别共享变量之间的约束条件

识别共享变量之间的约束条件十分重要,因为这会影响到并发访问策略的定制。

下面举例说明。

在库存管理中有个合理库存的概念,库存量不能太高,也不能太低,它有一个上限和一个下限。下面使用代码说明。

SafeVM中,声明了两个成员变量upperlower,分别代表了库存上限和下限,我们使用原子类AtomLong来定义这两个变量。由于原子类是线程安全的,所以这两个成员变量的set()方法就不需要同步。

public class SafeWM {
// 库存上限
private final AtomicLong upper = new AtomicLong(0);
// 库存下限
private final AtomicLong lower = new AtomicLong(0); // 设置库存上限
void setUpper(long v){
upper.set(v);
}
// 设置库存下限
void setLower(long v){
lower.set(v);
}
// 省略其他业务代码
}

但是,我们需要注意,两个共享变量之间是有一个约束条件的:库存下限要小于库存上限

于是我们就要加入参数校验,我们在方法setUpper()和方法setLower()中加入检验语句:

// 设置库存上限
void setUpper(long v){
// 检查参数合法性
if (v < lower.get()) {
throw new IllegalArgumentException();
}
upper.set(v);
}
// 设置库存下限
void setLower(long v){
// 检查参数合法性
if (v > upper.get()) {
throw new IllegalArgumentException();
}
lower.set(v);
}

看似上面的代码没有什么问题,但是仔细分析一下,便可以发现其实存在竞态条件。(校验的结果依赖线程的执行顺序)

例如,库存初始的上限和下限分别为(2,10)。线程 A 调用 setUpper(5) 将上限设置为 5,线程 B 调用 setLower(7) 将下限设置为 7。线程A和线程B同时执行,会发现线程A和线程B都可以同时通过校验,导致最终库存为(7,5)。

线程A执行时,下限还没有被线程 B 设置,还是 2,而 5>2;线程B执行时,上限还没有被线程 A 设置,还是 10,而 7<10。

在没有识别出库存下限要小于库存上限这个约束条件之前,我们制定的并发访问策略是利用原子类,但是这个策略,完全不能保证库存下限要小于库存上限这个约束条件。

所以,在设计阶段,我们一定要识别出所有共享变量之间的约束条件,如果约束条件识别不足,很可能导致制定的并发访问策略南辕北辙。

制定并发访问策略

指定并发访问策略,从方案思想上来看,可以从以下三个方面入手:(在前一篇博客的小结中也提到过)

  1. 避免共享

    上篇文章介绍的线程封闭技术。

  2. 不变模式

    例如Actor模式,CSP模式以及函数式编程的基础都是不变模式。

  3. synchronized同步机制和并发容器

除了以上方案思想,还有一些宏观原则需要了解。

  1. 优先使用成熟的工具类

    使用已经设计好的工具类,避免重复造轮子。

  2. 迫不得已才使用低级的同步原语

    低级的同步原语主要指的是 synchronizedLockSemaphore 等,虽然看上去简单,但使用起来还是要万分小心。

  3. 避免过早优化

    先保证线程安全性,再考虑优化性能。

小结

主要是学习参考[1]时的学习总结笔记,没有加入太多自己的思考或者补充点,(◞‸◟ )积累还不够。

要好好撸起袖子加油干!( ̄^ ̄)ゞ

参考:

[1]极客时间专栏王宝令《Java并发编程实战》

【Java并发基础】利用面向对象的思想写好并发程序的更多相关文章

  1. C#基础第七天-作业答案-利用面向对象的思想去实现名片-动态添加

    class Card { private string name; public string Name { get { return name; } set { name = value; } } ...

  2. C#基础第七天-作业-利用面向对象的思想去实现名片-动态添加

    1.利用面向对象的思想去实现: (增加,修改,删除,查询,查询全部)需求:根据人名去(删除/查询).指定列:姓名,年龄,性别,爱好,电话. 多条添加 , 动态添加 名片 本系列教程: C#基础总结之八 ...

  3. C#基础第六天-作业-利用面向对象的思想去实现名片

    1.利用面向对象的思想去实现: (增加,修改,删除,查询,查询全部)需求:根据人名去(删除/查询).指定列:姓名,年龄,性别,爱好,电话. 本系列教程: C#基础总结之八面向对象知识点总结-继承与多态 ...

  4. C#基础第六天-作业答案-利用面向对象的思想去实现名片

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. 2018.3.5 Java语言基础与面向对象编程实践

    Java语言基础与面向对象编程实践 第一章 初识Java 1.Java特点 http://www.manew.com/blog-166576-20164.html Java语言面向对象的 Java语言 ...

  6. 黑马程序员——OC语言基础语法 面向对象的思想

    Java培训.Android培训.iOS培训..Net培训.期待与您交流! (以下内容是对黑马苹果入学视频的个人知识点总结)(一)基础语法 1)关键字 @interface.@implementati ...

  7. python基础----以面向对象的思想编写游戏技能系统

    1. 许多程序员对面向对象的思想都很了解,并且也能说得头头是道,但是在工作运用中却用的并不顺手. 当然,我也是其中之一. 不过最近我听了我们老师的讲课,对于面向对象的思想有了更深的理解,今天决定用一个 ...

  8. C语言用面向对象的思想写贪吃蛇

    大概一年前这时候,接触C语言一个月,那时候知之甚少,对面向对象只觉”可远观而不可亵玩“,而且会看到很多言论说C语言就是面向过程的语言,C++就是面向对象的语言.不过,不记得什么时候在网上看到过一篇博文 ...

  9. 2018.6.20 Java考试试题总结(Java语言基础与面向对象编程)最新版

    Java考试试题总结 一.单选题(每题1分 * 50 = 50分) 1.java程序的执行过程中用到一套JDK工具,其中javac.exe指( B ) A.java语言解释器 B.java字节码编译器 ...

随机推荐

  1. 天猫SSM项目学习记录(一)----第一个相对完整的SSM项目

    来源:  http://how2j.cn/k/tmall_ssm/tmall_ssm-1516/1516.html?p=78908 目的:记录一个相对完整的SSM项目模板 1.工具:idea2018商 ...

  2. react 报红错误汇总

    react  报红错误汇总 一.Uncaught TypeError: Cannot read property 'value' of undefined 未知类型错:无法读取未定义的属性“value ...

  3. 小小知识点(二十一)如何修改PPT母版上无法直接点击修改的文字

    1. 进入PPT后,选择下图右上角红色圈出的“视图”,接着选择下方红色圈出的“幻灯片母版”: 2.点击进入母版,如下图所示,最上面一栏第一个选项变成了“幻灯片母版”,在下面一栏最右边变成了“关闭母版视 ...

  4. 从头学pytorch(十六):VGG NET

    VGG AlexNet在Lenet的基础上增加了几个卷积层,改变了卷积核大小,每一层输出通道数目等,并且取得了很好的效果.但是并没有提出一个简单有效的思路. VGG做到了这一点,提出了可以通过重复使⽤ ...

  5. schedule of 2016-11-7~2016-11-10(Monday~Thursday)——1st semester of 2nd Grade

    most important things to do 1.joint phd preparations 2.journal paper to write 3.solid fundamental kn ...

  6. WPF 添加提示动画

    下面放一张效果图: 那么具体是怎么实现呢: 前端XAML中: <Image Source="/Images/tips.png" HorizontalAlignment=&qu ...

  7. es6种for循环中let和var区别

    let和var区别: for(var i=0;i<5;i++){ setTimeout(()=>{ console.log(i);//5个5 },100) } console.log(i) ...

  8. Hexo 中使用 emoji 和 tasks

    替换为 markdown-it 今天在迁移博客项目的时候,发现原来在 hugo 中可以使用的 Emoji 和 tasks 功能都不能正常使用了,查询了一下原因,主要是因为 hexo 默认的解析器是 h ...

  9. Sql Server执行一条Update语句很慢,插入数据失败

    今天同事要我修改服务器数据库里面的2条数据,查看服务器上的SQL Server数据库的时候,发现这几天数据没有添加成功,然后发现磁盘很快就满了,执行Update语句时,执行半天都提示还在执行,查询语句 ...

  10. 使用Merkle树检测数据不一致(翻译)

    背景 Cassandra的逆熵功能使用Merkle树来检测副本之间的数据不一致. 定义 Merkle树是一种哈希树,其中的叶子包含各个数据块的哈希值,父节点包含其各自的子节点的哈希值.它提供了一种有效 ...