设计模式 之 单例模式

ε祈祈猫儿з 提交于 2020-10-31 09:27:53

设计模式 之 单例模式

保证系统中一个类只有一个实例。

使用场景:

  • 需要频繁实例化的对象;
  • 创建时消耗资源过多,又常被使用的对象;

常见单例模式

1、饿汉式

package com.foruo.learn.designmode.singleton;

/**
 * 单例 - 饿汉式(即类被加载时实例化对象)
 * @author GaoYuan
 * @date 2018/5/4 上午8:09
 */
public class SingletonDemoEntity {
    /** 注意 static */
    private static SingletonDemoEntity singletonDemoEntity = new SingletonDemoEntity();

    /** 注意 private */
    private SingletonDemoEntity(){}

    public static SingletonDemoEntity getInstance(){
        return singletonDemoEntity;
    }

    public static void main(String[] args){
        MyThread myThread = new MyThread();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);

        thread1.start();
        thread2.start();
        thread3.start();

        //此处可见三次打印相同内容,则表示是同一个对象
    }
}

class MyThread extends Thread{

    @Override
    public void run() {
        System.out.println(SingletonDemoEntity.getInstance().hashCode());
    }

}

2、懒汉式 - 普通 - 线程不安全 不推荐

package com.foruo.learn.designmode.singleton;

/**
 * 单例 - 懒汉式(即类加载时没有实例化,调用取得实例的方法getInstance()的时候才实例化对象)
 * @author GaoYuan
 * @date 2018/5/4 上午8:09
 */
public class SingletonDemoEntity2 {
    /** 注意 static 并且没有初始化 */
    private static SingletonDemoEntity2 singletonDemoEntity;

    /** 注意 private */
    private SingletonDemoEntity2(){}

    /** 注意 synchronized */
    public static synchronized SingletonDemoEntity2 getInstance(){
        if(singletonDemoEntity == null){
            singletonDemoEntity = new SingletonDemoEntity2();
        }
        return singletonDemoEntity;
    }

    public static void main(String[] args){
        MyThread2 myThread = new MyThread2();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);

        thread1.start();
        thread2.start();
        thread3.start();

        //此处可见三次打印相同内容,则表示是同一个对象
    }

}

class MyThread2 extends Thread{

    @Override
    public void run() {
        System.out.println(SingletonDemoEntity2.getInstance().hashCode());
    }

}

3、懒汉式 - 双重锁 - 线程安全适用高并发 推荐

package com.foruo.learn.designmode.singleton;

/**
 * 单例 - 懒汉式 - 双重锁(即类加载时没有实例化,调用取得实例的方法getInstance()的时候才实例化对象)
 * @author GaoYuan
 * @date 2018/5/4 上午8:09
 */
public class SingletonDemoEntity3 {
    /** 注意 static 并且没有初始化 */
    private static SingletonDemoEntity3 singletonDemoEntity = null;

    /** 注意 private */
    private SingletonDemoEntity3(){}

    /**
     * 注意 synchronized 不在方法上,而在if里面,这样只有第一次才进行同步,之后的每次调用因为已经有对象,则不会再进入同步方法中
     * 高并发的场景下,又要使用懒汉式,则推荐使用 此方法
     * */
    public static SingletonDemoEntity3 getInstance(){
        if(singletonDemoEntity == null){
            synchronized (SingletonDemoEntity3.class){
                if(singletonDemoEntity == null) {
                    singletonDemoEntity = new SingletonDemoEntity3();
                }
            }
        }
        return singletonDemoEntity;
    }

    public static void main(String[] args){
        MyThread3 myThread = new MyThread3();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);

        thread1.start();
        thread2.start();
        thread3.start();

        //此处可见三次打印相同内容,则表示是同一个对象
    }

}

class MyThread3 extends Thread{

    @Override
    public void run() {
        System.out.println(SingletonDemoEntity3.getInstance().hashCode());
    }

}

比较

撇开2,比较1饿汉式与3懒汉式

  • 1饿汉式 在类加载的时候就创建实例对象,不管后续是否被调用,也有可能浪费一定的空间,但省去了每次调用判断的时间

  • 3懒汉式(线程安全)在第一次调用时进行同步判断,但也仅仅是第一次需要同步,之后的每次只需要进行简单的if判断即可,相比较饿汉式多耗费些时间,如果从来没有被调用,则不会占据内存空间

综述:

  • 懒汉式需要考虑线程安全;
  • 不要用反射调用单例;
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!