Java中饿汉式与懒汉式单例设计模式的写法与分析

饿汉式:

package com.xyz.bean;

/**
 * 饿汉式单例设计模式
 * 私有化静态final 属性
 * 私有化构造
 * 提供public static 的genInstance方法
 */
public class Singleton1 {
    private static final Singleton1 singleton1 = new Singleton1();

    private  Singleton1(){

    }

    public static Singleton1 getInstance(){
        return singleton1;
    }
}

懒汉式(不加锁):

package com.xyz.bean;

/**
 *  懒汉式单例
 *  提供私有的对象 并开始置空
 *  在调用时初始化
 */
public class Singleton2 {
    private static Singleton2 singleton2 = null;

    private Singleton2(){

    }

    public static Singleton2 getInstance(){
        if(singleton2==null){
            return new Singleton2();
        }
        return singleton2;
    }
}

懒汉式可能会出现的问题,使用多线程进行测试。

package test;

import com.xyz.bean.Singleton1;
import com.xyz.bean.Singleton2;
import org.junit.Test;

public class TestSingleton extends Thread {

    private  static Singleton2 singleton2 = null;
    @Override
    public void run() {
        this.singleton2 = Singleton2.getInstance();
        System.out.println(this.singleton2+":"+singleton2.getClass());
    }

    @Test
    public void getSingleton(){
        //继承Thread类 重写run方法
        Thread ts = new TestSingleton();
       //启动线程
        ts.start();
        singleton2 = Singleton2.getInstance();
        System.out.println(singleton2+":"+singleton2.getClass());
        //使用匿名内部类实现多线程
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Singleton1 singleton1 = Singleton1.getInstance();
                System.out.println(singleton1+":"+singleton1.getClass());
            }
        });
        thread1.start();
        //实现Runnable 接口 重写run方法
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Singleton1 singleton1 = Singleton1.getInstance();
                System.out.println(singleton1+":"+singleton1.getClass());
            }
        };
        new Thread(runnable).start();
    }
}

/**运行结果:
* com.xyz.bean.Singleton2@593634ad:class com.xyz.bean.Singleton2
* com.xyz.bean.Singleton2@52b59e9c:class com.xyz.bean.Singleton2
* com.xyz.bean.Singleton1@c87cc8f:class com.xyz.bean.Singleton1
* com.xyz.bean.Singleton1@c87cc8f:class com.xyz.bean.Singleton1
* */

可以看出,不加锁的懒汉式,再遇到多线程时,会产生两个不一样的引用。为此,给它上锁!

package com.xyz.bean;

public class Singleton3 {

    private static Singleton3 singleton3 = null;

    private Singleton3(){
    }
    //给Singleton3 加上类级锁
    public static synchronized Singleton3 getInstance(){
        if(singleton3 == null){
            singleton3 = new Singleton3();
        }
            return singleton3;
        }
}

然后在TestSingleton加上如下测试:

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Singleton3 singleton3 = Singleton3.getInstance();
                System.out.println(singleton3+":"+this.getClass());
            }
        });
        thread2.start();

        System.out.println(Singleton3.getInstance()+":"+this.getClass());

测试通过,两者获得的引用一致!

总结:

1.饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,不管创建多少个实例对象,永远都只分配了一个static变量,缺点是会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。

2.懒汉式是非线程安全的,可以使用同步锁synchronized,好处是可以延迟加载。另外也可以使用静态内部类来实现锁的功能。

如:

public class Singleton {    
    private static class Init {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       return Init.INSTANCE;    
    }    
}    

猜你喜欢

转载自blog.csdn.net/u010074463/article/details/81458808