【Java并发基础】利用面向对象的思想写好并发程序
前言
下面简单总结学习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
中,声明了两个成员变量upper
和lower
,分别代表了库存上限和下限,我们使用原子类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。
在没有识别出库存下限要小于库存上限这个约束条件之前,我们制定的并发访问策略是利用原子类,但是这个策略,完全不能保证库存下限要小于库存上限这个约束条件。
所以,在设计阶段,我们一定要识别出所有共享变量之间的约束条件,如果约束条件识别不足,很可能导致制定的并发访问策略南辕北辙。
制定并发访问策略
指定并发访问策略,从方案思想上来看,可以从以下三个方面入手:(在前一篇博客的小结中也提到过)
避免共享
上篇文章介绍的线程封闭技术。
不变模式
例如
Actor
模式,CSP
模式以及函数式编程的基础都是不变模式。synchronized
同步机制和并发容器
除了以上方案思想,还有一些宏观原则需要了解。
优先使用成熟的工具类
使用已经设计好的工具类,避免重复造轮子。
迫不得已才使用低级的同步原语
低级的同步原语主要指的是
synchronized
、Lock
、Semaphore
等,虽然看上去简单,但使用起来还是要万分小心。避免过早优化
先保证线程安全性,再考虑优化性能。
小结
主要是学习参考[1]时的学习总结笔记,没有加入太多自己的思考或者补充点,(◞‸◟ )积累还不够。
要好好撸起袖子加油干!( ̄^ ̄)ゞ
参考:
[1]极客时间专栏王宝令《Java并发编程实战》
【Java并发基础】利用面向对象的思想写好并发程序的更多相关文章
- C#基础第七天-作业答案-利用面向对象的思想去实现名片-动态添加
class Card { private string name; public string Name { get { return name; } set { name = value; } } ...
- C#基础第七天-作业-利用面向对象的思想去实现名片-动态添加
1.利用面向对象的思想去实现: (增加,修改,删除,查询,查询全部)需求:根据人名去(删除/查询).指定列:姓名,年龄,性别,爱好,电话. 多条添加 , 动态添加 名片 本系列教程: C#基础总结之八 ...
- C#基础第六天-作业-利用面向对象的思想去实现名片
1.利用面向对象的思想去实现: (增加,修改,删除,查询,查询全部)需求:根据人名去(删除/查询).指定列:姓名,年龄,性别,爱好,电话. 本系列教程: C#基础总结之八面向对象知识点总结-继承与多态 ...
- C#基础第六天-作业答案-利用面向对象的思想去实现名片
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 2018.3.5 Java语言基础与面向对象编程实践
Java语言基础与面向对象编程实践 第一章 初识Java 1.Java特点 http://www.manew.com/blog-166576-20164.html Java语言面向对象的 Java语言 ...
- 黑马程序员——OC语言基础语法 面向对象的思想
Java培训.Android培训.iOS培训..Net培训.期待与您交流! (以下内容是对黑马苹果入学视频的个人知识点总结)(一)基础语法 1)关键字 @interface.@implementati ...
- python基础----以面向对象的思想编写游戏技能系统
1. 许多程序员对面向对象的思想都很了解,并且也能说得头头是道,但是在工作运用中却用的并不顺手. 当然,我也是其中之一. 不过最近我听了我们老师的讲课,对于面向对象的思想有了更深的理解,今天决定用一个 ...
- C语言用面向对象的思想写贪吃蛇
大概一年前这时候,接触C语言一个月,那时候知之甚少,对面向对象只觉”可远观而不可亵玩“,而且会看到很多言论说C语言就是面向过程的语言,C++就是面向对象的语言.不过,不记得什么时候在网上看到过一篇博文 ...
- 2018.6.20 Java考试试题总结(Java语言基础与面向对象编程)最新版
Java考试试题总结 一.单选题(每题1分 * 50 = 50分) 1.java程序的执行过程中用到一套JDK工具,其中javac.exe指( B ) A.java语言解释器 B.java字节码编译器 ...
随机推荐
- 最小化centos7.4系统静默安装oracle12.2
一 orace简介 ORACLE(甲骨文)公司.Oracle Database (甲骨文数据库) 是一个具有对象和可扩展标记语言(XML)功能的关系数据库,提供的以分布式数据库为核心的一组软件产品,是 ...
- 最详细的自定义Spring Boot Starter开发教程
1. 前言 随着Spring的日渐臃肿,为了简化配置.开箱即用.快速集成,Spring Boot 横空出世. 目前已经成为 Java 目前最火热的框架了.平常我们用Spring Boot开发web应用 ...
- 选题Scrum立会报告+燃尽图 04
此作业的要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/8682 组长:杨天宇 组员:魏新,罗杨美慧,王歆瑶,徐丽君 组名:组长 ...
- Redis-NoSQL入门和概述(一)
NoSQL简史及定义 NoSQL 这个术语最早是在 1998 年被Carlo Strozzi命名在他的轻量的,开源的关系型数据库上的,但是该数据库没有提供标准的SQL接口:在2009 年再次被Eric ...
- 清晰架构(Clean Architecture)的Go微服务: 程序容器(Application Container)
清晰架构(Clean Architecture)的一个理念是隔离程序的框架,使框架不会接管你的应用程序,而是由你决定何时何地使用它们.在本程序中,我特意不在开始时使用任何框架,因此我可以更好地控制程序 ...
- 我该如何学习spring源码以及解析bean定义的注册
如何学习spring源码 前言 本文属于spring源码解析的系列文章之一,文章主要是介绍如何学习spring的源码,希望能够最大限度的帮助到有需要的人.文章总体难度不大,但比较繁重,学习时一定要耐住 ...
- JavaScript substring()
JavaScript substring() 方法 参数 描述 start 必需.一个非负的整数,规定要提取的子串的第一个字符在 stringObject 中的位置. stop 可选.一个非负的整数, ...
- 【转】推荐给初级Java程序员的3本进阶书
ImportNew 注: 原作者在这篇文章中介绍3本不错的技术书籍.作者认为这些书籍对新手或者学生而言尤其有帮助.通过一些基础性的教程入门后,我们可以使用Java做基础性的编程.然而,当我们需要从初级 ...
- 开启我的python之路,第一节,git版本管理工具
git版本管理工具 一.git功能与结构 1.Git是分布式管理系统,服务端和客户端都有版本控制功能,都能进行代码的提交,合并 2.git分为工作区,暂存区,本地仓库和远程仓库 二.git安装与查看 ...
- phpstudy nginx设置CORS跨域不起作用的可能解决方法
今天搞了半天的跨域问题,想通过nginx配置跨域,希望以后本地调试程序都不用为这件事烦心.无非就是设置几个请求头: add_header Access-Control-Allow-Origin *; ...