设计模式:单例模式

本文详细介绍了单例模式的四大原则、特点以及四种实现方式:饿汉模式、懒汉模式、双重验证懒汉模式和静态内部类饿汉模式,并通过测试分析了各模式的线程安全性和实例创建时机。单例模式主要用于确保类只有一个实例,并提供全局访问点,适合用于管理共享资源的场景。
摘要由CSDN通过智能技术生成

单例模式四大原则:

1.构造器必须私有化,私有化后类加载一次后无法在通过其他手段创建对象。

2.通过方法或枚举获取对象,在类加载时实例化对象,且无法通过外部手段创建额外对象。

3.确保实例只有一个,尤其是多线程环境。

4.确保反序列换时不会重新构建对象。

单例模式的特点:

       1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

单例模式分类:

饿汉模式:线程安全,但是存在资源消耗,类加载时创建对象。

/**
 * 单例模式(饿汉模式)
 * 线程安全的,类加载时就分配了资源
 */
public class HungrySingletonPattern {

    private static HungrySingletonPattern singleton = new HungrySingletonPattern();

    private HungrySingletonPattern (){

    }

    public static HungrySingletonPattern getInstall() throws InterruptedException {
        Thread.sleep(1000);
        return singleton;
    }

}

测试:

public class Test {

    public static void main(String[] args) {
        for(int i = 0;i < 10; i++){
            new Thread(()->{
                try {
                    HungrySingletonPattern singletonPattern = HungrySingletonPattern.getInstall();
                    System.out.println(singletonPattern);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

}

输出:
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf
com.wonder.cube.test.designmode.HungrySingletonPattern@4388eabf

可以看出是同一个对象

2.懒汉模式(又叫饱汉模式)

/**
 * 单例模式(懒汉模式)
 * 在用到该单例对象时才创建对象
 * 多线程下单例模式无效,线程不安全
 */
public class LazySingletonPattern {

    private static LazySingletonPattern singleton;

    private LazySingletonPattern(){

    }

    public static LazySingletonPattern getInstance() throws InterruptedException {
        if(singleton == null){
            // 模拟做一些事情,会把线程都聚集在此,测试用
            Thread.sleep(1000);
            singleton = new LazySingletonPattern();
        }
        return singleton;
    }
}

测试:

public class Test {

    public static void main(String[] args) {
        for(int i = 0;i < 10; i++){
            new Thread(()->{
                try {
                    LazySingletonPattern singletonPattern = LazySingletonPattern.getInstance();
                    System.out.println(singletonPattern);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

输出:

com.wonder.cube.test.designmode.LazySingletonPattern@4f0c4707
com.wonder.cube.test.designmode.LazySingletonPattern@3996d457
com.wonder.cube.test.designmode.LazySingletonPattern@4f0c4707
com.wonder.cube.test.designmode.LazySingletonPattern@1e057600
com.wonder.cube.test.designmode.LazySingletonPattern@4f0c4707
com.wonder.cube.test.designmode.LazySingletonPattern@626213bf
com.wonder.cube.test.designmode.LazySingletonPattern@90472a2
com.wonder.cube.test.designmode.LazySingletonPattern@19281561
com.wonder.cube.test.designmode.LazySingletonPattern@4533731f
com.wonder.cube.test.designmode.LazySingletonPattern@616831d4

出现了多个对象,原因:

线程1在进入到 == null判断时是ture,因此进入到内部执行sleep,此时并未创建任何对象,接下来线程2进入到代码,此时==null依然成立,都阻塞在sleep中,剩下的线程也是同样的道理,当sleep结束后,进入到==null的代码中的线程都执行了一遍singleton = new LazySingletonPattern();的代码,因此出现了不同对象。

3.双重验证懒汉模式:

/**
 * 双重验证懒汉模式(线程安全)
 *
 */
public class LazyAgainSingletonPattern {

    private static volatile LazyAgainSingletonPattern pattern;

    private LazyAgainSingletonPattern(){

    }

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

volatile关键字不加的话,会出现jvm乱序的问题,具体问题请百度一下,此处不做解释。

加了synchronized锁后,每个线程排队执行,就不会出现上述问题了。

测试:

public class Test {

    public static void main(String[] args) {
        for(int i = 0;i < 10; i++){
            new Thread(()->{
                try {
                    LazyAgainSingletonPattern singletonPattern = LazyAgainSingletonPattern.getInstance();
                    System.out.println(singletonPattern);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

输出:

com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457
com.wonder.cube.test.designmode.LazyAgainSingletonPattern@3996d457

4.静态内部类饿汉模式

/**
 * 懒汉模式
 * 静态内部类模式,线程安全的,应为对象是被static 修饰,只有一份,且在需要用到时才创建
 * 缺点:无法传参
 */
public class InnerStaticHungrySingletonPattern {

    private InnerStaticHungrySingletonPattern(){

    }

    private static class Hungry{

        private static InnerStaticHungrySingletonPattern pattern = new InnerStaticHungrySingletonPattern();

        protected static InnerStaticHungrySingletonPattern getInstance(){
            return pattern;
        }
    }

    public static InnerStaticHungrySingletonPattern getInstance(){
        return Hungry.getInstance();
    }
}

jvm在加载类的时候,不会加载该类的内部类,只有在用到该内部类的时候才会去加载该类的内部类。此方法具有了懒加载模式,同时又符合饿汉模式,唯一的缺点是不能传参数。

测试:

com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
com.wonder.cube.test.designmode.InnerStaticHungrySingletonPattern@55477623
 

在具体项目中可以根据需求选择不同的单例模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值