Java 设计模式 5 —— 单例模式

单例模式

定义

确保一个类只有一个实例,并提供一个全局访问点。

通常要创建对象,基本上是离不开new的。在某些特定的场景下,整个应用的生命周期内只需要一个实例对象,那么new显然已经不适用了。

在之前文章中介绍Hibernate时,就曾经使用过单例模式。在静态代码块中初始化了sessionFactory,显然全局的sessionFactory有且只有一个。

public class HibernateUtils {

    private static SessionFactory sessionFactory;

    static {
        Configuration configuration = new Configuration().configure();
        sessionFactory = configuration.buildSessionFactory();
    }

    private HibernateUtils() {}

    public static Session openSession() {
        Session session = sessionFactory.openSession();
        return session;
    }

    public static Session getCurrentSession() {
        Session session = sessionFactory.getCurrentSession();
        return session;
    }
}

还有数据库连接时的DataSource等都需要使用单例模式。

如果一个类拥有私有的构造函数,那么它就无法通过new来创建实例对象。因此,声明私有的构造函数是设计单例模式的第一步。

实现方式

public class Singleton {

    private static Singleton singleton = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return singleton;
    }
}

优点:写法简单,就是在类装载的时候就完成实例化,是线程安全的。

缺点:在类装载的时候就完成实例化,没有达到懒加载的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。


public class Singleton {

    private static Singleton singleton;

    static {
        singleton = new Singleton();
    }

    private Singleton() {}

    public static Singleton getInstance() {
        return singleton;
    }
}

优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费。

缺点:线程不安全。


public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费。

缺点:线程不安全。

public class Main {
    public static void main(String[] args) {
        new Thread(()-> System.out.println(Singleton.getInstance())).start();
        new Thread(()-> System.out.println(Singleton.getInstance())).start();
        new Thread(()-> System.out.println(Singleton.getInstance())).start();
        new Thread(()-> System.out.println(Singleton.getInstance())).start();
        new Thread(()-> System.out.println(Singleton.getInstance())).start();
    }
}

开启五个线程获取单例对象,结果:

com.xiaobai.singleton.Singleton@581e62ab
com.xiaobai.singleton.Singleton@1f7e6c66
com.xiaobai.singleton.Singleton@1f7e6c66
com.xiaobai.singleton.Singleton@1f7e6c66
com.xiaobai.singleton.Singleton@1f7e6c66

public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费,同时也是线程安全的。

缺点:使用synchronized同步,会损失部分性能。


public class Singleton {

    private volatile static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized(Singleton.class) {
              singleton = new Singleton();
            }
        }
        return singleton;
    }
}

优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费。

缺点:线程不安全,虽然用synchronized同步了,但是就算通过if (singleton == null)后任然会存在线程安全问题。


public class Singleton {

    private volatile static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized(Singleton.class) {
              if (singleton == null) {
                singleton = new Singleton();
              }
            }
        }
        return singleton;
    }
}

优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费;双重检验,是线程安全的。

缺点:使用synchronized同步,会损失部分性能。


public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

优点:因为是静态内部类,有懒加载的效果,在需要时才会实例化,不会造成内存的浪费,同时也是线程安全的。


public class Singleton {}

public enum ForSingleton {
    INSTANCE;
    private Singleton singleton;

    ForSingleton() {
        singleton = new Singleton();
    }

    public Singleton getInstance() {
        return singleton;
    }
}

优点:有懒加载的效果,也是线程安全的。

利用枚举类型必须是私有的特点来实现单例模式。

发布了14 篇原创文章 · 获赞 0 · 访问量 103

猜你喜欢

转载自blog.csdn.net/aaacccadobe/article/details/104017502