1.设计模式之单例模式(Singleton)

Pattern1-Singleton

什么是单例模式

  • 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。该设计为了保证在一个进程中,某个类有且仅有一个实例。
  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

单例的实现方式有四种,下面分别进行介绍:

方式一 :饿汉式(简单易用)类加载到内存中时,就进行初始化。

public class Single01 {
  	
  	//1.保证实例只能在类中进行实例化,其他类中不能进行实例化
    private Single01(){}    

    //2.创建静态final实例
    private static final Single01 INSTANCE = new Single01();
    
    //3.提供其他对象访问实例的方法
    public static Single01 getInstance(){
        return INSTANCE;
    }


    //4.公共方法
    public void test() {
        System.out.println("single01");
    }
    
    //进行测试,看单例模式否是创建成功
    public static void main(String[] args) {
        Single01 single1 = new Single01();
        Single01 single2 = new Single01();

        System.out.println(single1 == single2);
        //结果是true,表示两个创建的是一个对象。

    }

}

  • 优缺点
  • 类加载到内存后,就实例化一个单例,JVM保证线程安全,
  • 保证每一个class只会load内存一次,static是在class在load内存中以后
  • 就开始实例化的,也只保证初始化一次。
  • ★简单实用,推荐使用!
  • 唯一缺点:不管用到与否,类装载时就完成实例化

方式二:懒汉式(lazy loading)

  • 和第一种方式不同的是在需要的时候才会进行实例的创建
  • 虽然实现了按需初始化的目的,但是却不是线程安全的,具体实现如下。
public class Single02 {

    private Single02(){}

    private static Single02 INSTANCE;

    //按需进行实例化
    public static Single02 getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Single02();
        }
        return INSTANCE;
    }

}

此时为什么说是线程不安全的呢?在进行getInstance()时,加入此时有两个线程都执行到了if(INSTANCE == null){}这个条件,而且都执行通过了,这时候就会创建两个实例对象,导致单例模式失败,线程不安全。

  • 为了展示这一个线程不安全的状态,下面进行一个测试:
  • 为了使测试效果更明显,我们让在getInstance时停顿一下,修改内容如下:
 //按需进行实例化
    public static Single02 getInstance(){
        if(INSTANCE == null){
            try {
            	//进程睡眠10毫秒
                Thread.sleep(10);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            INSTANCE = new Single02();
        }
        return INSTANCE;
    }
  • 下面创建十个进程来同时常见单例对象,查看结果是否为单例。结果表明不是单例模式;
    public static void main(String[] args) {
        for(int i=0; i<10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Single02.getInstance());
                }
              }
            ).start();
        }
    }

结果:singleton.Single02@4a140fe5
singleton.Single02@49fb8056
singleton.Single02@9d30fed
singleton.Single02@2abb5f1c
singleton.Single02@692db0ef
singleton.Single02@7e92ee0
singleton.Single02@3fe9e503
singleton.Single02@12cddde4
singleton.Single02@6eb7e2c8
singleton.Single02@13f938d6

  • 对于该方式,也可以通过加锁来实现线程安全;但是降低了系统的效率
public class Single02 {

    private Single02(){}

    private static  Single02 INSTANCE;

    //按需进行实例化
    public static synchronized Single02 getInstance(){
        if(INSTANCE == null){
            INSTANCE = new Single02();
        }
        return INSTANCE;
    }

}

★方式三:静态内部类方式(工作中常用方式)

  • 对于此方式,JVM保证单例,JVM加载class时只加载一次,保证的单例
  • 加载外部类时不会加载内部类,这样可以实现懒加载(按需加载)
public class Single04 {

    private Single04(){}
	
	//内部类实现懒加载
    private static class Single04Holder{
        private static final Single04 INSTANCE = new Single04();
    }

    public static Single04 getInstance(){
        return Single04.Single04Holder.INSTANCE;
    }
}

方式四:枚举单例(完美主义)

  • Java创始人之一在《Effective Java》中提出使用枚举单例的方式,
  • 不仅可以解决线程同步,还可以防止反序列化。
public enum Single05 {
    INSTANCE;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值