java并发编程实践学习(2)--对象的组合
- 先验条件(Precondition):某些方法包含基于状态的先验条件。例如,不能从空队列中移除一个元素,在删除元素前队列必须处于非空状态。基于状态的先验条件的操作成为依赖状态操作。
- 在单线程中,如果某操作无法满足先验条件,就只能失败,但在并发程序中先验条件可能会由于其他线程执行的操作而变成真。
- java中等待某个条件为真的各种内置机制(包括等待和通知机制)都与内置加锁紧密关联。
- 所有权和封装性总是相关联的:对象封装它拥有的所有权,对象对它的封装的状态拥有所有权。
- 发布了某个可变对象的引用,那就不再拥有独占的控制权。
- 容器类通常表现出一种“所有权分离”的形式。
4.1设计线程安全的类
在设计线程安全类的过程中,需要包含以下三个基本要素:
- 找出构成对象状态的所有变量
- 找出约束状态变量的不可变性条件
- 建立对象状态的并发访问管理策略
4.3委托给线程安全的类
可以将共享资源委托给一个线程安全的类。比如ConcurrentHashMap,copyOnWriteArrayList.
如果一个类时由多个独立且线程安全的状态变量组成,并且在所有的操作中都不包含无效状态转换,那么可以将线程安全性委托给底层状态变量。
下面是一个监控车辆位置的实例。其中Point是线程安全不可变的类。
/**
* 不可变
*/
@Immutable
class Point{
public final int x,y; Point(int x,int y ) {
this.x = x;
this.y = y;
}
} /**
* 委托给线程安全类的车辆追踪器
*/
@ThreadSafe
class DelegatingVehicleTracker{
private final ConcurrentHashMap<String,Point> locations;
private final Map<String,Point> unmodifiableMap; public DelegatingVehicleTracker(Map<String,Point> points) {
this.locations = new ConcurrentHashMap<>(points);
this.unmodifiableMap = Collections.unmodifiableMap(locations);
} public Map<String,Point> getLocations(){
return unmodifiableMap;
} public Point getLocation(String id){
return locations.get(id);
} public void setLocation(String id,int x,int y){
if(locations.replace(id,new Point(x,y)) == null){
throw new IllegalArgumentException("invalid vehicle name:"+id);
}
}
}
如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量。
同样是车辆追踪,我想要获取位置,还可以修改位置,安全性问题可以交给底层SafePoint:
/**
* 线程安全且可变的Point类
*/
@ThreadSafe
class SafePoint{
@GuardedBy("this") private int x,y;
private SafePoint(int[] a){
this(a[0],a[1]);
}
public SafePoint(SafePoint p){
this(p.get());
}
public SafePoint(int x,int y){
this.x = x;
this.y = y;
}
public synchronized int[] get(){
return new int[] {x,y};
}
public synchronized void set(int x,int y){
this.x =x;
this.y = y;
}
} /**
* 安全发布底层状态的车辆追踪器
*/
@ThreadSafe
class PublishingVehicleTracker{
private final Map<String,SafePoint> locations;
private final Map<String,SafePoint> unmodifiableMap; PublishingVehicleTracker(Map<String, SafePoint> locations, Map<String, SafePoint> unmodifiableMap) {
this.locations = locations;
this.unmodifiableMap = unmodifiableMap;
} public Map<String,SafePoint> getLocations(){
return unmodifiableMap;
}
public SafePoint getLocation(String id){
return locations.get(id);
}
public void setLocation(String id,int x,int y){
if (!locations.containsKey(id))
throw new IllegalArgumentException("invalid vehicle name:"+id);
locations.get(id).set(x,y);
}
}
4.5将同步策略文档化
在文档中说明客户代码需要了解的线程安全性保证,以及代码维护人员需要了解的同步策略。
synchronized,volatile或者任何一个线程安全类都对应于某种同步策略,用于在并发访问时确保数据的完整性。一定要在忘记之前记录下来。
可以使用@GuardedBy("this")或者别的来注释锁。
java并发编程实践学习(2)--对象的组合的更多相关文章
- Java并发编程实战 之 对象的共享
上一篇介绍了如何通过同步多个线程避免同一时刻访问相同数据,本篇介绍如何共享和发布对象,使它们被安全地由多个进程访问. 1.可见性 通常,我们无法保证执行读操作的线程能看到其他线程写入的值,因为每个线程 ...
- JAVA并发编程学习笔记------对象的可见性及发布逸出
一.非原子的64位操作: 当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值,这种安全性保证被称为最低安全性.最低安全性适用于绝大多数变量 ...
- 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象
Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...
- [Java 并发] Java并发编程实践 思维导图 - 第四章 对象的组合
依据<Java并发编程实践>一书整理的思维导图. 第一部分: 第二部分:
- Java 并发编程(四):如何保证对象的线程安全性
01.前言 先让我吐一句肺腑之言吧,不说出来会憋出内伤的.<Java 并发编程实战>这本书太特么枯燥了,尽管它被奉为并发编程当中的经典之作,但我还是忍不住.因为第四章"对象的组合 ...
- Java并发编程锁系列之ReentrantLock对象总结
Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...
- 《Java并发编程实战》第三章 对象的共享 读书笔记
一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见 ...
- 【Java并发编程一】线程安全和共享对象
一.什么是线程安全 当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的 ...
- Java并发编程(五):Java线程安全性中的对象发布和逸出
发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...
随机推荐
- 开源库Magicodes.WeChat.SDK总体介绍
目录 1 概要 1 2 主要特点 2 3 架构图 8 3.1 构造器——WeChatSDKBuilder 8 3.2 函数管理器——WeChatF ...
- MySql Windws 下自动备份脚本
这几天正在做一个 使用MySQL数据库的项目,目前项目已经完成了,当部署好项目之后,正在考虑如何自动备份MySql数据库的问题,我在网上找了一下资料终于解决了,特此记录一下. @echo off e ...
- 使用statsd+graphite+grafana构建业务及性能监控模块
近些年随着DevOps概念越来越收到重视,除了传统的Splunk,Zabbix外在开源领域也有越来越多的软件可供使用.从数据收集,时序数据库,图形展示等主要方面有各类可扩展的软件用于搭建一个数据监控平 ...
- Ubuntu全新安装firefox最新版本
Ubuntu默认安装firefox,但是自带的软件仓库是不会随firefox更新的,我在使用中老是提示flash插件需要激活,提示中可选的解决方式有三种 1.更新flash插件,但是跳转到adobe的 ...
- SQLSERVER取当前月第一天和最后一天
--本月第一天: select dateadd(dd,-day(getdate())+1,getdate()) --本月最后一天: SELECT dateadd(ms,-3,DATEADD(mm, ...
- 了解一下JavaScript的未来——ECMAScript5
神马是EcmaScript5 首先得先搞清楚ECMAScript是神马,我们知道JavaScript或者说LiveScript最开始是Netscape搞出来的,后来微软也跟进搞出了Jscript,Sc ...
- Java面向对象思想解决猜拳问题
第一个面向对象的程序: 一个控制台猜拳小游戏: 第一步选择角色: 第二部选择剪刀,石头,布,与电脑进行PK: 第三部选择继续或者选择结束; 结束显示比赛的局数,以及各自赢得的分数: 设计思路 分析问题 ...
- 关于stm32的正交解码
关于正交解码,我先解释何为正交解码,,,,其实名字挺高大上的,,,,还是先说编码器吧 看一下我用过的一种编码器 编码器的 线 数 ,是说编码器转一圈输出多少个脉冲,,,如果一个编码器是500线,,,说 ...
- [常见问题]在Linux下执行Redis命令不起作用.
redis 127.0.0.1:6379> 这个后面无论输入什么命令都没有返回 ok 或者其他的信息,一直保持截图的状态: 解决方法:在SecureCRT中设置Options-->Sess ...
- spring cvc-elt.1: Cannot find the declaration of element 'beans'解决办法
转载自http://blog.csdn.net/legendj/article/details/9950963 今天在写spring aop示例的时候,在spring.xml文件中添加spring a ...