三种方式实现java单例

版权声明:转载请标明来源 https://blog.csdn.net/u010652576/article/details/78448692

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 通过部分源码分析,内部类和外部类的访问和顺序。

猜你喜欢

转载自blog.csdn.net/u010652576/article/details/78448692