vlambda博客
学习文章列表

单例模式【创建型模式】

1、这篇文章使用了一个工具格式化的,排版虽然看起来不是很好,但是真的比我自己排版要好。

2、没想到这篇文章发表在CSDN上竟然上了推荐。

3、单例模式面试经常被问到,今天看视频总结了下面的内容,大家可以好好看看,然后用自己的话总结下面试怎么说。

4、后面会一直学习完23种设计模式,都会分享出来。

所谓单例模式,就是对某个类只能存在一个对象实例,并且该类只提供一个获取其对象实例的方法(静态方法)

单例模式一共有八种方式

1、饿汉式 (静态常量)

2、饿汉式 (静态代码块)

3、懒汉式 (静态方法内部判断,线程不安全)

4、懒汉式 (线程安全,同步方法)

5、懒汉式 (线程不安全,同步代码块)

6、双重检查

7、静态内部类

8、枚举


1、饿汉式

1-1:饿汉式(静态常量)

1、构建

    1、构造器私有化(防止 new)     2、类的内部创建对象     3、向外暴露一个静态的公共方法(getInstance)

2、代码演示

public class Main { // 测试 public static void main(String[] args) { Singleton one = Singleton.getInstance(); Singleton two = Singleton.getInstance(); System.out.println(one == two); // true System.out.println("one.hashCode() = " + one.hashCode()); // 两个hashcode相同 System.out.println("two.hashCode() = " + two.hashCode()); }
}
class Singleton { // 1、私有化,防止 new private Singleton(){} // 2、本类内部创建实例 private final static Singleton instance = new Singleton(); // 3、提供一个公有的静态方法,返回实例对象 public static Singleton getInstance(){ return instance; }}

3、分析

3-1:优缺点

优点:写法比较简单,就是在类加载的时候完成实例化。避免了线程同步问题。缺点:在类加载的时候就完成实例化,没有达到懒加载的效果。如果从始至终从未使用过这个实例,则会造成内存浪费。


1-2:饿汉式(静态代码块)

1、代码演示 (测试和上面的测试一样,就不赘述了)

class Singleton { // 1、私有化,防止 new private Singleton(){} // 2、创建变量 private static Singleton instance; // 3、静态创建对象 static { instance = new Singleton(); } // 4、提供一个公有的静态方法,返回实例对象 public static Singleton getInstance(){ return instance; }}

2、优缺点,和上面一样不再赘述。


2、懒汉式

1、懒汉式(线程不安全的)

1、代码演示

class Singleton { // 1、私有化,防止 new private Singleton(){} // 2、创建变量 private static Singleton instance; // 3、提供一个公有的静态方法,返回实例对象 public static Singleton getInstance(){ if (instance == null){ instance = new Singleton(); } return instance; }}

2、优缺点

优点:起到了懒加载的作用缺点:线程不安全。(一个线程进入 if 语句后,还没来得及往下执行,另一个线程也通过了判断语句,这时候就会产生多个实例 )


2、懒汉式(使用 synchronized 同步方法, 保证线程安全)

1、代码演示

class Singleton { // 1、私有化,防止 new private Singleton(){} // 2、创建变量 private static Singleton instance; // 3、提供一个同步静态方法,返回实例对象。解决线程安全问题 public synchronized static Singleton getInstance(){ if (instance == null){ instance = new Singleton(); } return instance; }}

2、优缺点

优点:解决了线程安全的问题。缺点:方法使用了同步,效率太低了。


3、懒汉式 (线程不安全,同步代码块)

不可以这样写,它连最起码的线程安全都无法保证。

1、代码演示

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


3、双重检查

1、代码演示

class Singleton {
private Singleton(){}
private volatile static Singleton instance;
public static Singleton getInstance(){ if (instance == null){ // 1 synchronized(Singleton.class){ // 2 if (instance == null){ instance = new Singleton(); } } } return instance; }}

说明:volatile可以保证可见性、有序性,还有禁止指令重排序。比如当我们线程A已经执行到了 2,线程B执行到了 1。这个时候线程A执行结束创建了对象,B再进来了发现对象已经创建了(volatile的作用)就不再创建了。而之后的线程直接在第一个if就被挡住了。

2、优缺点

优点:做到了懒加载、解决了线程安全问题和效率问题。


7、静态内部类

1、代码演示

class Singleton {
private Singleton(){}
private static class SingletonInstance{ private static final Singleton INSTANCE = new Singleton(); }
public static Singleton getInstance(){ return SingletonInstance.INSTANCE; }}

说明:

外部类装载的时候,内部类不会进行装载的。当我们调用getInstance的时候内部类会进行装载,装载的过程是线程安全的。

2、优缺点

优点:避免线程安全问题,满足了延迟加载,效率高。


8、枚举

public class Main { public static void main(String[] args) { Singleton one = Singleton.INSTANCE; Singleton two = Singleton.INSTANCE; System.out.println(one == two); System.out.println(one.hashCode()); System.out.println(two.hashCode()); }}enum Singleton { INSTANCE; public void fun(){ System.out.println("fun..."); }}

2、优缺点

优点:避免线程安全问题,而且还能防止反序列化重新创建新的对象。


9、其它

1、JDK里面哪使用到了单例模式?

    Runtime里面就用到了单例模式的饿汉模式,它把构造方法私有化了,然后直接使用静态常量创建对象。


2、单例模式注意事项

单例保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统的性能。当想实例化一个单例类的时候,必须记住使用相应的获取对象的方法,而不是使用new单例模式使用场景:需要频繁的进行创建和销毁的对象、创建对象时消耗过多或消费资源过多(重量级对象),但又经常使用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工程等)