java的单例模式主要分为:饿汉模式和懒汉模式
饿汉模式:饿汉很饥饿,所以直接先new出来,再提供。
饿汉模式代码:加载class文件的时候就实例化。
package com.jkf.redis;
public class HungryManSingleton {
public static void main(String[] args) {
HungrySingleton singleton = HungrySingleton.getInstatnc();
singleton.print();
}
}
class HungrySingleton{
//对象加载的时候,就初始化
public static HungrySingleton singleton = new HungrySingleton();
//提供静态访问的方法
public static HungrySingleton getInstatnc(){
return singleton;
}
public void print(){
System.out.println("this is hungry jkf");
}
}
懒汉模式:加载class文件的时候,并不实例化,等需要用得时候再实例化。那么懒汉模式需要满足以下情形:
1 class文件加载的时候,并不会进行实例化。2 当需要获取实例对象是必须解决多线程并发访问的问题。如果加载的时候不进行实例化,那么就需要排除饿汉模式了。常见的懒汉模式主要有两种:1 双重锁机制(dubbo check lock DCL模式)
,2 内部类创建模式。
第一种懒汉模式DCL:
package com.jkf.redis;
//双重检查锁机制 懒汉模式
public class DoubleCheckLockSingletonTest {
public static void main(String[] args) {
DoubleCheckSingleton singleton = DoubleCheckSingleton.getInstance();
singleton.print();
}
}
class DoubleCheckSingleton{
//通过volatile限制jvm的命令重排,导致singleton初始化不完全,即singleton可见,但是还未初始化完全,因为对象从加载到实例化并不保证全部顺序执行,只保证每个阶段的开启时间是顺序执行的,不保证结束时间。
public static volatile DoubleCheckSingleton singleton;
public static DoubleCheckSingleton getInstance(){
//第一次检查非空
if(singleton == null){
synchronized (DoubleCheckSingleton.class) {
//第二次检查非空,主要限制其他通过第一次检查的等待线程
if(singleton == null){
singleton = new DoubleCheckSingleton();
}
}
}
return singleton;
}
public void print(){System.out.println("this is dcl hungry singleton");}
}
第二种:静态内部类
package com.jkf.redis;
/**通过内部类实现懒汉形式的单例**/
public class SingletonStaticClass {
public static void main(String[] args) {
Singleton singleton = Singleton.getSingleton();
singleton.print();
}
}
//静态内部类:
class Singleton{
static{
System.out.println("this is main class");
}
public static Singleton singleton;
public static Singleton getSingleton(){
System.out.println("main class getSingleton=====");
singleton = SingletonFatory.singleton;
return singleton;
}
//静态内部类
static class SingletonFatory{
static{
System.out.println("this is static inner class");
}
private static Singleton singleton = new Singleton();
}
public void print(){
System.out.println("this is static jkf");
}
}
//输出内容:
this is main class
main class getSingleton=====
this is static inner class
this is static jkf
//从输出内容中,可以看出来,加载Singleton时,并没有加载内部类,当调用getSingleton方法后,才进行了内部类的加载初始化,此时才进行了Singleton的实例化。
静态内部类方案的原理:
1 延迟实例化:主要是通过jvm的class加载机制,静态的内部类可以看做一个正常的class文件,因此加载Singleton时,并不会加载内部类SingletonFactory,这就实现了延迟加载。当getSingleton()方法调用了SingletonFactory时,就会触发SingletonFactory的加载,此时SingletonFactory就会实例化Singleton,又因为jvm的classLoader机制在加载class文件的时候进行了synchronized,保证当多个线程请求时,只能有一个线程进行class文件的加载,那么实例化时也只有一个对象。
懒汉模式的另一种实现方式:通过枚举类实现,因为上述几种的单例模式的实现,无法解决通过反射进行实例化,但是枚举实现单利可以避免,具体代码这块不是特别的清楚,有需要的请大家自行搜索。
参考文章:1 http://blog.csdn.net/zhang_yanye/article/details/50344447 通过个人代码示例,展示内部类的加载
2 http://blog.csdn.net/zhang_yanye/article/details/50301511 通过部分源码分析,内部类和外部类的访问和顺序。