1.单例模式

发布时间 2023-08-15 17:19:44作者: jsqup

单例模式

  • 定义:程序运行时,在java虚拟机中只存在该类的一个实例对象。
  • demo:
package mode;

public class SingleDemo {
    // 创建SingleDemo单例对象
    private static SingleDemo instance = new SingleDemo();
    // 将构造方法设成私有的,这样该类就不会被实例化
    private SingleDemo() {}

    public static SingleDemo getInstance() {
        return instance;
    }

    public void showMessage() {
        System.out.println("这里是重要的信息");
    }
}
class SingleAply{
    public static void main(String[] args) {
        SingleDemo singleDemo = SingleDemo.getInstance();
        singleDemo.showMessage();
    }
}

实现方式

懒汉式-线程不安全

懒汉式_线程不安全
优点 1.起到了延迟加载的效果
缺点 1.只能在单线程下使用
2.如果在多线程下,一个线程进入了if(single==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这是便会产生多个实例。所以多线程不可以使用
结论 在实际开发中,不要使用这种方式
public class LazyNotSafe {
    private static LazyNotSafe instance;
    private LazyNotSafe() {}

    public LazyNotSafe getInstance() {
        if (instance == null) {
            instance = new LazyNotSafe();
        }
        return instance;
    }
}

懒汉式-线程安全

懒汉式_线程安全
优点 1.解决了线程不安全问题
缺点 1.效率太低,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。
2.而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低。
结论 在实际开发中,不要使用这种方式
public class LazySafe {
    private static LazySafe instance;
    private LazySafe() {}

    public static synchronized LazySafe getInstance() {
        if (instance == null) {
            instance = new LazySafe();
        }
        return instance;
    }
}

懒汉式-线程不安全同步代码块

懒汉式_同步代码块
优点 延迟加载
缺点 1.本意是对线程安全的懒汉式进行改进,因为其同步方法效率太低,改为同步产生的实例化代码块
2.线程不能同步。假如一个线程进入了if(instance==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例
注意:synchronized同步代码块中,当释放锁后,会继续向下执行
结论 在实际开发中,不能用这种方式
public class LazyNoSafePiece {
    private static LazyNoSafePiece instance;
    private LazyNoSafePiece() {}

    public LazyNoSafePiece getInstance() {
        if (instance == null) {
            synchronized(LazyNoSafePiece.class) {
                instance = new LazyNoSafePiece();
            }
        }
        return instance;
    }
}

饿汉式-静态变量/静态代码块

饿汉式_静态变量/静态代码块
优点 在类加载的时候完成了实例化,避免了线程同步问题。
缺点 在类装载的时候就完成实例化,没有达到延迟加载的效果。如果从头到尾未使用过这个实例,则会造成内存的浪费
结论 这种单例模式可以使用,但可能会造成内存的浪费
class HungrySafe {
    private static HungrySafe instance = new HungrySafe();
    private HungrySafe() {}
    public static HungrySafe getInstance() {
        return instance;
    }
}

class HungrySafe2 {
    private static HungrySafe2 instance;
    private HungrySafe2() {}
    static {
        instance = new HungrySafe2();
    }
    public static HungrySafe2 getInstance() {
        return instance;
    }
}

双重检查(推荐使用)

双重检查
优点 1.线程安全
2.延迟加载
3.效率较高
4.实例化代码只用执行一次,后面再次访问时,判断第一层if(xxx==null),直接return实例化对象,也避免的反复进行方法同步。
结论 在实际开发中,推荐使用
public class DoubleCheck {
    private DoubleCheck doubleCheck;
    private DoubleCheck() {}
    
    public DoubleCheck getInstance() {
        if (doubleCheck == null) {
            synchronized(DoubleCheck.class) {
                if (doubleCheck == null) {
                    doubleCheck = new DoubleCheck();
                }
            }
        }
        return doubleCheck;
    }
}

静态内部类(推荐使用)

优势
如何保证实例时只有一个线程?
即如何保证线程安全?
类的静态属性只会在第一次加载类的时候初始化,在类进行初始化时,别的线程是无法进入的,所以线程安全
如何实现延迟加载 利用静态内部类,不是在xxx类被装载时立即实例化,而是在调用getInstance方法时,才会装载xxx类,从而完成xxx类的实例化
public class InnerClass {
    // volatile:一有修改就更新到主存中去
    private static volatile InnerClass instance;
    private InnerClass() {}

    private static class InnerInstance {
        private final static InnerClass instance = new InnerClass();
    }

    public static InnerClass getInstance() {
        return InnerInstance.instance;
    }
}

枚举