以下代码整理别人的,加上自己的认识,做些注释,当是笔记。
(1)第一种方式:通过final static 关键字直接让类加载时就初始化,简称恶汉式
public class SingletonClass {
private static final SingletonClass instance = new SingletonClass();
public static SingletonClass getInstance() {
return instance;
}
private SingletonClass() {
}
}
因为如上代码,类一加载就初始化了,如果类没有用到无缘消耗了资源。
所以提出延长初始化的概念(lazy loaded),即需要时再初始化。
(2)第二种方式:懒汉式,使用synchronized关键字同步方法体
public class SingletonClass {
private static SingletonClass instance = null;
public synchronized static SingletonClass getInstance() {
if (instance == null) {
instance = new SingletonClass();
}
return instance;
}
private SingletonClass() {
}
}
由于懒汉式只需第一次判断即可,如果此类需要初始化资源消耗过多时,无疑会造成性能问题,所以提出
(3)所谓的double-checked方式,懒汉式升级版
public class SingletonClass {
private static SingletonClass instance = null;
public static SingletonClass getInstance() {
if (instance == null) {//首先判断,提高性能,因为只有第一次才需要synchronized
synchronized (SingletonClass.class) {
if (instance == null) {//保证多线程条件下单例唯一
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
但JAVA语言中却不能使用此double-checked模式,因为
语言在编译时需要编译优化,即在不改变原来语义的情况下,通过调整语句顺序,来让程序运行的更快。这个过程成为reorder。
JVM只是一个标准,并不是实现。JVM中并没有规定有关编译器优化的内容,也就是说,JVM实现可以自由的进行编译器优化。
所以,JVM就存在两种初始化对象的模型:
开辟内存空间,调用构造方法,然后指针指向内存。
开辟内存空间,指针指向内存,然后调用构造方法。
针对第二种情况,加入线程B现在调用getInstance方法,而线程A刚好在创建对象,而此时线程B判断instance不为null,事实上null还没真正初始化成功,所以出错。
(3)解决方法:
//通过volatile关键字——被volatile修饰的写变量不能和之前的读写代码调整,读变量不能和之后的读写代码调整,但需要JDK1.5以上版本支持
public class SingletonClass {
private volatile static SingletonClass instance = null;
public static SingletonClass getInstance() {
if (instance == null) {
synchronized (SingletonClass.class) {
if(instance == null) {
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
//静态内部类处理,事实上是单例第一种方式的修改。(第一,起到了延迟初始化的作用;第二,优化了synchronized性能)
public class SingletonClass {
private static class SingletonClassInstance {
private static final SingletonClass instance = new SingletonClass();
}
public static SingletonClass getInstance() {
return SingletonClassInstance.instance;
}
private SingletonClass() {
}
}
(1)第一种方式:通过final static 关键字直接让类加载时就初始化,简称恶汉式
public class SingletonClass {
private static final SingletonClass instance = new SingletonClass();
public static SingletonClass getInstance() {
return instance;
}
private SingletonClass() {
}
}
因为如上代码,类一加载就初始化了,如果类没有用到无缘消耗了资源。
所以提出延长初始化的概念(lazy loaded),即需要时再初始化。
(2)第二种方式:懒汉式,使用synchronized关键字同步方法体
public class SingletonClass {
private static SingletonClass instance = null;
public synchronized static SingletonClass getInstance() {
if (instance == null) {
instance = new SingletonClass();
}
return instance;
}
private SingletonClass() {
}
}
由于懒汉式只需第一次判断即可,如果此类需要初始化资源消耗过多时,无疑会造成性能问题,所以提出
(3)所谓的double-checked方式,懒汉式升级版
public class SingletonClass {
private static SingletonClass instance = null;
public static SingletonClass getInstance() {
if (instance == null) {//首先判断,提高性能,因为只有第一次才需要synchronized
synchronized (SingletonClass.class) {
if (instance == null) {//保证多线程条件下单例唯一
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
但JAVA语言中却不能使用此double-checked模式,因为
语言在编译时需要编译优化,即在不改变原来语义的情况下,通过调整语句顺序,来让程序运行的更快。这个过程成为reorder。
JVM只是一个标准,并不是实现。JVM中并没有规定有关编译器优化的内容,也就是说,JVM实现可以自由的进行编译器优化。
所以,JVM就存在两种初始化对象的模型:
开辟内存空间,调用构造方法,然后指针指向内存。
开辟内存空间,指针指向内存,然后调用构造方法。
针对第二种情况,加入线程B现在调用getInstance方法,而线程A刚好在创建对象,而此时线程B判断instance不为null,事实上null还没真正初始化成功,所以出错。
(3)解决方法:
//通过volatile关键字——被volatile修饰的写变量不能和之前的读写代码调整,读变量不能和之后的读写代码调整,但需要JDK1.5以上版本支持
public class SingletonClass {
private volatile static SingletonClass instance = null;
public static SingletonClass getInstance() {
if (instance == null) {
synchronized (SingletonClass.class) {
if(instance == null) {
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
//静态内部类处理,事实上是单例第一种方式的修改。(第一,起到了延迟初始化的作用;第二,优化了synchronized性能)
public class SingletonClass {
private static class SingletonClassInstance {
private static final SingletonClass instance = new SingletonClass();
}
public static SingletonClass getInstance() {
return SingletonClassInstance.instance;
}
private SingletonClass() {
}
}