“同步”确保了操作的原子性执行,但它还有其它重要的方面:memory visibility.我们不但要确保当一个线程在使用一个对象的时候,其它线程不能修改这个对象,而且还要保证该线程在修改对象状态时,其它线程能够看到该线程对对象所做的改变。

可以通过显式的同步语句或内建类库的同步机制以保证对象的正确发布。

3.1. Visibility

3.1.1. Stale Data

3.1.2. Non-atomic 64-bit Operations(针对没有声明为volatile的double和long)

Java内存模型要求读取和写入操作都是原子性的,但对于非volitile的long和double变量,jvm通过两个32位操作来完成一个64位的读写。

因此,当在一个多线程程序中有double和long型的共享变量是,对它的读写一定要加volatile或通过锁来同步

3.1.3. Locking and Visibility

3.1.4. Volatile Variables

锁能确保可见性和原子性,volitale只能保证可见性

3.2. Publication and Escape

发布一个对象是指该对象在它当前的上下文范围之外是可用的,如存储一个引用,使其他代码能够访问、通过非私有的方法返回自己、或者是将自己传递给另一个类的方法中(特别注意!!)。

//Publishing an Object
//发布一个对象,通过静态字段引用它
public static Set<Secret> knownSecrets; public void initialize(){
knownSecrets = new HashSet<Secret>();
}
//Allowing Internal Mutable State to Escape.Don't do this.
//私有变量通过公共方法逃逸 class UnsafeStates{
private String[] states = new String[]{"ak","al",...}; public String[] getStates(){
return states;
}
}

发布一个对象,有可能同时会发布它字段锁引用的对象,这些对象通过它的公有变量或共有的get方法发布出来,要小心无意的泄漏。

小心,不要在你的构造方法里面泄漏了你的对象!!!

public class ThisEscape{
public ThisEscape(EventSource source){
source.registerListener(new EventListener{
public void onEvent(Event e){
doSomething(e);
}
});
}
}

3.2.1. Safe Construction Practices

从构造函数中发布一个对象(匿名内部类实现),会导致当前对象也跟着发布,但是当前对象的构造函数还没有返回,即它不一定被正确的构建就已经发布了

Do not allow the this reference to escape during construction.

一个常见错误是在构造函数中起一个线程,这样会提前发布this引用。

//ThisEscape 改进版本
public class SafeListener{
private final EventListener listener; private SafeListener(){
listener = new EventListener(){
public void onEvent(Event e){
doSomething(e);
}
};
} public static SafeListener newInstance(EventSource source){
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}

3.3. Thread Confinement

3.3.1. Ad-hoc Thread Confinement

3.3.2. Stack Confinement

就是本地变量

//本地原是类型和引用类型的线程封闭
public int loadTheArk(Collection<Animal> candidates){
SortedSet<Animals> animals;
int numPairs = 0;
Animal candidate = null;
animals = new TreeSet<Animal>(new SpeciesGenderComparator());
animals.addAll(candidates);
for(Animal a:animals){
if(candidate == null || !candidate.isPotentialMate(a))
candidate = a;
esle{
ark.load(new AnimalPair(candidate,a));
++ numPairs;
candidates = null;
}
}
return numPairs;
}

3.3.3. ThreadLocal

//using ThreadLocal to ensure thread confinement
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>(){
public Connection initialValue(){
return DriverManager.getConnection(dburl);
}
}; public static Connection getConnection(){
return connectionHolder.get();
}

该技术适用于频繁申请临时对象的操作,即每来一个线程,就分配一个临时对象的情况。但是不要滥用,会增加耦合性。

3.4. Immutability

不可变对象总是线程安全的。

//一个不可变对象
@Immutable
public final class /threeStooges{
private fianl Set<String> stooges = new HashSet<String>(); public ThreeStooges(){
stooges.add("Moe");
atooges.add("Larry");
stooges.add("Curly");
}
public boolean isStooge(String name){
return stooges.contain(name);
}
}

3.4.1 Final Fields

就像对象的字段如果不需要保持对外可见,用private修饰一样,若字段不需要修改,那么也要设置为final

3.4.2 Example: Using Volatile to Publish Immutable Objects

3.5. Safe Publication

3.5.1 Improper Publication:When Good Objects Go Bad

3.5.2 Immutable Objects and initialization Safety

3.5.3 Safe Publication Idioms

要安全发布一个对象,对该对象的引用与对象的状态必须同时对其他线程可见。一个正确构建的对象可以通过如下步骤被安全发布:

  • 使用静态初始化器初始化一个对象引用
  • 将引用存储为volatile或AtomicReference
  • 将引用存为一个正确构建的对象的final字段
  • 将引用存为一个字段,该字段用适当的锁来保护

推荐使用静态初始化器,如:

public static Holder holder = new Holder(12);

这样发布的对象一定是安全的。

3.5.4 Efectively immutable Objects

事实不可变对象(对象在发布后就不需要改变,但是技术上是可变的),在发布之后不会被修改的对象,那么只要保证安全发布就好了,由于后续不需修改,也就不用同步机制来保证可见性。例如,Date就是可变对象,但是假如你不去修改它,那么就不需要锁来保证可见性。

3.5.5 Mutable Objects

对象的发布需求取决于它的可变性:

  • 不可变对象可以通过任何机制发布
  • 事实不可变对象必须安全发布
  • 可变对象必须安全发布,而且必须线程安全或通过锁来保护

3.5.6 Sharing Objects Safely

当你发布一个对象,你要指定该对象应该被怎样访问

在并发程序中,使用和共享对象的最有效的策略是:

  • 线程封闭:该对象为该线程独有,其他线程无法修改
  • 只读共享:其它线程无法修改该对象,也就不会有线程问题,可以用不可变对象或事实不可变对象
  • 线程安全共享:一个线程安全的对象使用内部同步,那么多线程可以自由的获取或修改它而不需要额外的同步机制
  • 监视状态:一个受监视的对象只能通过持有正确锁的线程来访问。

JCIP chap3 share objects的更多相关文章

  1. The Truth About .NET Objects And Sharing Them Between AppDomains

    From http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx I have written already some ti ...

  2. Managing C++ Objects: 管理C++对象 —— 一些建议准则

    原文链接: Managing C++ Objects Here are some guidelines I have found useful for writing C++ classes. The ...

  3. AMD高级应用(翻译)

    Dojo now supports modules written in the Asynchronous Module Definition (AMD) format, which makes co ...

  4. 企业级nosql数据库应用与实战-redis

    一.NoSQL简介 1.1 常见的优化思路和方向 1.1.1 MySQL主从读写分离 由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力.读写集中在一个数据库上让数据库不堪重负,大部 ...

  5. Python 函数参数传递机制.

    learning python,5e中讲到.Python的函数参数传递机制是对象引用. Arguments are passed by assignment (object reference). I ...

  6. 超越村后端开发(4:API开发)

    1.users相关的api开发 1.在settings中添加APPID,SECRET 2.在apps/users/views.py内: from chaoyuecun.settings import ...

  7. 设计模式教程(Design Patterns Tutorial)笔记之二 结构型模式(Structural Patterns)

    目录 · Decorator · What is the Decorator Design Pattern? · Sample Code · Adapter · What is the Adapter ...

  8. facebook api之Access Tokens之Business Manager System User

    Business Manager System User Make programatic, automated actions on ad objects or Pages, or do progr ...

  9. [Forward]Ten Caching Mistakes that Break your App

    Caching large objects, duplicate objects, caching collections, live objects, thread unsafe caching a ...

随机推荐

  1. SQL Server中的锁

    死锁的类型 不同表之间的相互等待,第一个事务操作A->B, 第二个事务操作B->A - 每个事务都锁定对方下一步将要操作的表 同一张表之间的相互等待, 无索引导致的全表扫描,下文中说到的情 ...

  2. 解析大型.NET ERP系统 分布式应用模式设计与实现

    C/S架构的应用程序,将一些复杂的计算逻辑由客户端转移到服务器端可以改善性能,同时也为了其它方面的控制..NET Remoting在局域网内调用的性能相当不错.ERP系统中基于.NET Remotin ...

  3. NLB网路负载均衡管理器详解

    序言 在上一篇配置iis负载均衡中我们使用啦微软的ARR,我在那篇文章也中提到了网站的高可用性,但是ARR只能做请求入口的消息分发服务,这样如果我们的消息分发服务器给down掉啦,那么做再多的应用服务 ...

  4. 阿里的weex框架到底是什么

    title: 阿里的weex框架到底是什么 date: 2016-09-27 10:22:34 tags: vue, weex category: 技术总结 --- weex 工作原理 首先看下官方的 ...

  5. DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(2)

    上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(1)> 阅读目录: 抽离 IRepository 并改造 Reposi ...

  6. [摘录]第三部分 IBM文化(2)

    第二十二章 原则性领导 在一个组织程序已经变得不受其来源和内容的约束,而且其编纂出来的组织宗旨已经代替了个人责任的组织之中,你所面临的首要任务,就是要全盘抹掉这个程序本身,以便让整个封闭的系统呼吸新鲜 ...

  7. 【NLP】Python NLTK 走进大秦帝国

    Python NLTK 走进大秦帝国 作者:白宁超 2016年10月17日18:54:10 摘要:NLTK是由宾夕法尼亚大学计算机和信息科学使用python语言实现的一种自然语言工具包,其收集的大量公 ...

  8. Vertica 安装,建库,新建测试用户并授予权限,建表,入库

    测试环境:RHEL 6.4 + Vertica 6.1.3-7 需求:搭建Vertica数据库3节点的测试环境,建立测试用户,建表,测试数据入库. 1.各节点关闭防火墙和SELinux,配置主机名,I ...

  9. nodejs中使用http请求返回值为html时乱码问题

    今天用nodejs进行http请求时返回的数据是一个html文件,然后我还是按照以前解析json数据的方法.果不其然报错了:SyntaxError: Unexpected token  in JSON ...

  10. 怎样把win7系统下的屏幕设置成护眼的非常柔和的豆沙绿色?

    经常面对电脑会导致眼睛过度疲劳,白色对眼睛的刺激是最大的,所以,最好不要用白色做电脑背景色 设置方法如下: 在桌面点右键选"个性化",接着点主窗口底部的"窗口颜色&quo ...