首页 > 代码库 > java并发编程的艺术,读书笔记第三章
java并发编程的艺术,读书笔记第三章
final域的内存语义
写final域的重排规则:禁止把final域的写重排序到构造方法之外,主要包括俩个个方面
1)JMM禁止编译器把final域的写重排序到构造方法之外
2)编译器会在final域写之后,构造函数return之前插入一个storestore屏障,这个屏障禁止处理器把final域的写重排序到构造方法之外
写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被
正确初始化过了,而普通域不具有这个保障
读final域的重排规则:在一个线程中,初次读对象引用与初次读该对象包含的final域,JMM处理器禁止重排这两个操作。编译器会在读final前插入loadload屏障
读final域的重排序规则可以确保:在读一个对象的final域之前,一定会先读包含这个final
域的对象的引用
对复合final域的重排规则:
在构造函数内对一个final引用对象的成员域内的写入,与随后在构造函数外把这个构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序
双重检查锁定与延迟初始化
基于volatile的解决方案
public class SafeDoubleCheckedLocking {
private volatile static Instance instance;
public static Instance getInstance() {
if (instance == null) {
synchronized (SafeDoubleCheckedLocking.class) {
if (instance == null)
instance = new Instance(); // instance为volatile,现在没问题了
}
}
return instance;
}
}
基于类初始化的解决方案
JVM在类初始化阶段(在class被加载后,且被线程使用前),会执行类的初始化。在执行类的初始化期间,JVM会获取一个锁,这个锁可以同步多个线程对同一个类的初始化。
基于这个特性,可以实现另一种线程安全的延迟初始化方案
public class InstanceFactory {
private static class InstanceHolder {
public static Instance instance = new Instance();
}
public static Instance getInstance() {
return InstanceHolder.instance ; // 这里将导致InstanceHolder类被初始化
}
}
根据java规范,发生如下情况,会被立即初始化
1)T是一个类,而且一个T类型的实例被创建。
2)T是一个类,且T中声明的一个静态方法被调用。
3)T中声明的一个静态字段被赋值。
4)T中声明的一个静态字段被使用,而且这个字段不是一个常量字段。
5)T是一个顶级类(Top Level Class,见Java语言规范的§7.6),而且一个断言语句嵌套在T
内部被执行。
类初始化的处理过程
类初始化的五个阶段
1) 通过class对象上的同步(获取class对象上的同步锁) 来控制类或者接口的初始化,这个获取锁的线程会一直等待,直到当前线程获取对象的初始化锁
2) 线程执行类a的初始化,同时线程b在对应的初始化锁的condition上等待
3)线程a设置状态位intilized,并呼唤所有condition等待的线程唤醒
4)线程b结束类的初始化
5)线程c执行类的初始化
本文出自 “iter工作总结” 博客,请务必保留此出处http://5855156.blog.51cto.com/5845156/1954184
java并发编程的艺术,读书笔记第三章