前言

下面简单总结学习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. iptables 添加80端口规则

    iptables -t filter -A INPUT -p tcp -s 10.0.0.0/24 -j DROP 在filter表的input链做规则丢弃10.0.0.0网段的ip包iptables ...

  2. spring注解之@Import注解的三种使用方式

    目录 1.@Import注解须知 2.@Import的三种用法 3.@Import注解的三种使用方式总结 @ 1.@Import注解须知 1.@Import只能用在类上 ,@Import通过快速导入的 ...

  3. 001JZ2440开发板熟悉与使用

  4. 【题解】BZOJ1034 [ZJOI2008]泡泡堂BNB(贪心)

    [题解]BZOJ1034 [ZJOI2008]泡泡堂BNB(贪心) 考虑直接模拟田忌赛马... 我的最小比你的大,直接上 我的最大比你的大,直接上 otherwise,我小换你大 考虑最劣,由于每次比 ...

  5. 洛谷$P$4301 $[CQOI2013]$新$Nim$游戏 线性基+博弈论

    正解:线性基 解题报告: 传送门! 这题其实就是个博弈论+线性基,,,而且博弈论还是最最基础的那个结论,然后线性基也是最最基础的那个板子$QwQ$ 首先做这题的话需要一点点儿博弈论的小技能,,,这题的 ...

  6. 程序员初学者参考 ---懂得基础语法后如何做一个自己的case?

    对于很多人来说,我懂java语法,甚至面向对象的特性啦这些都是有了解的,但我就是不会做项目,其实项目真有那么难吗? 对于基础不牢固的人来说,我还不会这个基础点,那个还没学呢,你让我做个项目,我保证做不 ...

  7. TVP思享 | 四个全新维度,极限优化HTTP性能

    导语 | 当产品的用户量不断翻番时,需求会倒逼着你优化HTTP协议.那么,要想极限优化HTTP性能,应该从哪些维度出发呢?本文将由TVP陶辉老师,为大家分享四个全新维度.「TVP思享」专栏,凝结大咖思 ...

  8. JavaScript中函数式编程中文翻译

    JavaScript 中的函数式编程 原著由 Dan Mantyla 编写 近几年来,随着 Haskell.Scala.Clojure 等学院派原生支持函数式编程的偏门语言越来越受到关注,同时主流的 ...

  9. 6、使用基元类型而不要使用 FCL 类型

    基元类型: int string object uint long ulong 等 ; FCL (Framework Class Library ) System.Int32 等. 一些定义在一些语言 ...

  10. python切片(获取一个子列表(数组))

    切片: 切片指从现有列表中,获取一个子列表 返回一个新列表,不影响原列表. 下标以 0 开始: list = ['红','绿','蓝','白','黑','黄','青']# 下标 0 1 2 3 4 5 ...