一起来学习设计模式:单例设计模式

前言:
单例设计模式也是非常常用的设计模式,比如我们所熟知的servlet他在Tomcat中是一个单例设计模式的实现,那到底单例设计模式是什么,有什么用呢?咱们一起来学习

1.什么是单例设计模式

有些对象我们只需要一个,比如配置文件,工具类,线程池,缓存,日志对象等等。如果我们创造多个实例会造成很多问题,比如占用资源过多,不一致的结果等。我们的单例设计模式就是保证实例只有一个,就能很好地避免这些问题
单例设计模式有两种:

  • 饿汉式
  • 懒汉式

2.饿汉式的实现

public class Singleton {
    //1.将构造方法设为私有,不允许外部直接创建对象
    private Singleton(){

    }
    //2.创建一个实例
    private static Singleton instance = new Singleton();

    //3提供一个用于获取实例的方法

    public static Singleton getInstance(){
        return instance;
    }
}

public class Test {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        //看是否指向同一个对象
        System.out.println(s1 == s2 ? "是同一个实例" :"不是同一个实例");
    }
}

image.png

从上面我们知道:
1.将构造方法设为私有,不允许外部直接创建对象
2.创建一个静态私有的实例
3.对外提供一个静态的方法,返回这个实例
4.访问的时候通过类名.静态方法获取
static修饰的是从类加载的时候就加载的,所以说当Singleton类加载的时候就加载了这个实例;我们可以形象地把加载的这个过程称为饿汉,因为他太饿了,所以想快点吃到东西(从类加载的时候就加载进来,迫不及待!imagine一下~)

3.懒汉式

public class Singleton2 {
    //将构造方法私有化
    private Singleton2(){

    }
    //声明类的唯一实例
    private static Singleton2 instance;
    //提供一个对外获取实例的方法
    public static Singleton2 getSingleton2() {
        if(instance == null)
        instance = new Singleton2();
        return instance;
    }


}

public class Test {
    public static void main(String[] args) {
        //饿汉式
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        //看是否指向同一个对象
        System.out.println(s1 == s2 ? "是同一个实例" :"不是同一个实例");
        //懒汉式
        Singleton2 s3 = Singleton2.getInstance();
        Singleton2 s4 = Singleton2.getInstance();
        System.out.println(s3 == s4 ? "是同一个实例" :"不是同一个实例");
    }
}

image.png

从上面我们知道:
1.私有化构造函数
2.声明一个实例
3.提供对外的方法,当第一个用户访问的时候就实例化instance对象,当第二个再访问的时候就不用再创建了,直接返回。看起来是不是很懒?后面的人都不想创建了,都拜托第一个访问的人了!!

4.两者的区别

1.饿汉模式加载类的时候比较慢,但运行的时候获取对象的速度比较快,线程安全
2.懒汉模式加载类的时候比较快,但是在运行时获取对象的速度比较慢,因为我们第一次访问的时候要创建对象,所以比较慢,同时懒汉模式线程是不安全的
3.为什么说饿汉模式的线程是安全的,懒汉模式线程是不安全的?举个例子,现在有两个线程thread1,thread2,他们都访问了上述的两种模式的对象,因为饿汉模式在加载的时候就实例化了,所以取到的值只有唯一一个,而懒汉模式,thread1有可能在if(instance == null)的时候还没开始实例化,thread2也加进来,这个时候就会有两个对象
测试饿汉式

public class TestThread implements Runnable {
    
    @Override
    public void run() {
       // 测试饿汉式
        Singleton  s1 = Singleton.getInstance();
        System.out.println("对象被创建" + s1 + " 当前线程" + Thread.currentThread().getName());
        System.out.println("hashCode" + s1.hashCode());
  
    }

    public static void main(String[] args) {

            TestThread t1 = new TestThread();
            TestThread t2 = new TestThread();
            new Thread(t1).start();
            new Thread(t2).start();

    }
}

image.png

测试懒汉式

public class TestThread implements Runnable {

    @Override
    public void run() {
       // 测试饿汉式
        Singleton2  s2 = Singleton2.getInstance();
        System.out.println("对象被创建" + s2 + " 当前线程" + Thread.currentThread().getName());
        System.out.println("hashCode" + s2.hashCode());

    }

    public static void main(String[] args) {

            TestThread t1 = new TestThread();
            TestThread t2 = new TestThread();
            new Thread(t1).start();
            new Thread(t2).start();

    }
}

image.png

Look看到效果了吧!

你可能感兴趣的:(一起来学习设计模式:单例设计模式)