Copyright © 2015 Powered by MWeb, Theme used GitHub CSS.
线程之间的通信机制有两种:共享内存和消息传递。
在共享内存的并发模型里,线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。
在消息传递的并发模型里,线程之间必须通过发送消息来显式进行通信。
同步是指程序中用于控制不同线程间操作发生相对顺序的机制。在共享内存模型里,同步是显式进行的。在消息传递的并发模型里,同步是隐式进行的。
Java的并发采用的是共享内存模型。

在执行程序时,为了提高性能,编译器和处理器会对指令做重排序。重排序分为3种类型:
编译器优化的重排序
编译器在不改变单线程程序语义的前提下。
指令级并行的重排序
如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
内存系统的重排序
对于编译器重排序,JMM的编译器重排序规则会禁止特定类型的编译器重排序,
对于处理器重排序,JMM的处理器重排序规则会要求Java编译器在生成指令序列时,插入特定类型的内存屏障指令,通过内存屏障指令来禁止特定类型的处理器重排序。
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。

重新排序上面两个操作的执行顺序,程序的执行结果就会被改变。
单线程在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。
as-if-serial语义的意思是:不管怎么重排序,单线程中程序的执行结果不能被改变。
happens-before具有传递性
如果程序是正确同步的,程序的执行将具有顺序一致性,即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同。
两个特性:
可见性
有序性
当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量。

从表中可以看出
为了实现volatile内存语义,在编译器生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序
JMM采用了比较保守的做法,在每个volatile写的后面或者在每个volatile读的前面插入一个StoreLoad屏障。
锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。
当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。
当线程获取锁时,JMM会把该线程对应的本地内存置为无效,从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。
锁释放与volatile写有相同的内存语义,锁获取与volatile读有相同的内存语义。
对final域的读写更像是普通的变量访问。
在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序
初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序
写final域的重排序规则禁止把final域的写重排序到构造函数之外。
Java程序中,有时候可能需要延迟对象的初始化操作,在使用对象时才进行初始化,但是很容易出问题。
下面是使用双重检查锁定来实现延迟初始化的示例代码:
public class SingleTon {
private static SingleTon INSTANCE = null;
private SingleTon() {
}
public static SingleTon getInstance() {
if (INSTANCE == null) {// ①
synchronized (SingleTon.class) {// ②
if (INSTANCE == null) { // ③
INSTANCE = new SingleTon();// 问题出在这里
}
}
}
return INSTANCE;
}
}
在线程执行到③位置处,可能INSTANCE不等于null,但INSTANCE引用的对象有可能还没完成初始化。

基于volatile的解决方案
把INSTANCE声明为volatile型,就可以实现线程安全的延迟初始化。
基于类初始化(静态内部类)的解决方案
public class SingleTon {
private static SingleTon INSTANCE = null;
private static class InstanceHolder{
public static SingleTon instance = new SingleTon();
}
public static SingleTon getInstance() {
return InstanceHolder.instance;//这里将导致InstanceHolder类被初始化
}
private SingleTon() {
}
}
根据Java语言规范,在首次发生下列任意一种情况时,一个类或接口类型T将被立即初始化
Java虚拟机规范规定了有且5中情况必须立即对类进行初始化

Copyright © 2015 Powered by MWeb, Theme used GitHub CSS.