单例设计模式是在软件系统中采用一定的方法,保证某个类只能存在一个实例对象,并且该类只能有一个静态方法来获取该对象。
注意下面各类实现方式中的测试代码都一样:需要注意导入的包路径即可。
package com.yefengyu; import com.yefengyu.type2.Singleton; public class Client { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); } }
1、实现方式一
该方式是静态常量实现的饿汉式(类加载的时候便创建了实例):
package com.yefengyu.type1; public class Singleton { //类内部实例化 private final static Singleton INSTANCE = new Singleton(); //构造器私有化,防止new对象 private Singleton() { } //对外提供公有方法调用 public static Singleton getInstance() { return INSTANCE; } }
1、类加载的时候实例化,防止多线程问题。
2、没有使用懒加载,类加载就产生对象,如果始终未使用则造成内存浪费。但是该对象只有一个,浪费空间也不是很大,可以使用,编写的时候非常简单。
2、实现方式二
该方式是静态代码块实现的饿汉式
package com.yefengyu.type2; public class Singleton { private final static Singleton INSTANCE; static { //使用静态代码块生成对象 INSTANCE = new Singleton(); } //构造器私有化,防止new对象 private Singleton() { } //对外提供公有方法调用 public static Singleton getInstance() { return INSTANCE; } }
该方式和方式一的优缺点类似。
3、实现方式三
该方式是同步方法实现懒汉式(只有第一次使用的时候才创建实例)
package com.yefengyu.type3; public class Singleton { private static Singleton instance; //构造器私有化,防止new对象 private Singleton() { } //只有在第一次使用的时候构造实例对象,使用synchronized避免多线程问题 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
1、解决了线程不安全问题
2、效率低下,每次调用该方法都要涉及锁的操作。
3、不推荐使用。
问:java设计模式的单例模式,在懒汉式中一开始声明的类的实例化对象为什么只用private static声明,但没有加final关键字?而在饿汉式中声明实例是使用了private static final修饰?
答:如果是final非static成员,必须在构造器、代码块、或者直接定义赋值;如果是final static成员变量,必须直接赋值或者在静态代码块中赋值。而在懒汉式中如果直接赋值就达不到延迟加载的效果。
4、实现方式四
该方式是同步代码块实现懒汉式。
package com.yefengyu.type4; public class Singleton { private static Singleton instance; //构造器私有化,防止new对象 private Singleton() { } //只有在第一次使用的时候构造实例对象,使用synchronized代码块和双重判断避免多线程问题,并且提供效率 public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
1、解决了线程不安全问题
2、效率高,只有前面的少数线程可能会获取锁,只要实例被创建,后面的线程一般只需第一个if判断就返回了对象。
3、推荐使用。
5、实现方式五
该方式是静态内部类实现懒汉式。
package com.yefengyu.type5; public class Singleton { private static Singleton instance; //构造器私有化,防止new对象 private Singleton() { } //静态内部类,在外部类加载的时候不会加载静态内部类 private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { //只有在使用到静态内部类的时候才会加载,并且通过类加载机制保证在初始化的时候只有一个实例产生 return SingletonInstance.INSTANCE; } }
1、线程安全,使用类加载机制保证初始化时只有一个线程。
2、外部类装载的时候静态内部类不会装载,只有使用的时候才会装载,因此达成了懒汉式的效果。
单例设计模式的使用场景?
一个对象即可完成所有的工作,无需大量创建对象消耗资源。比如一个长连接,建立起来就可以不断发送数据,此时如果每来一个请求就建立一个连接,那么资源会消耗殆尽。
多线程测试:针对懒汉式
测试代码:
for (int i = 0; i < 1000; i++) { new Thread(() -> { Singleton.getInstance(); }).start(); }
在new实例的时候加上打印,如:
public static synchronized Singleton getInstance() { if (instance == null) { System.out.println("创建实例"); instance = new Singleton(); } return instance; }