Java单例模式


什么是单例模式

单例模式是在程序中,一个类保证只有一个实例,并提供统一的访问入口。

为什么要用单例模式

  • 节省内存 节省计算
    • 如对象实例中的一样的,那就不用每次都创建一个对象
  • 方便管理
    • 因为单例提供一个统一的访问入口,不需要创建N多个对象,很多工具类都用了单例实现,如日志、字符串工具类
  • 保证结果正确
    • 比如统计网站的访问次数等等

单例的实现方式

  • 饿汉式
    • 程序启动的时候就会实例化
1 public class Singleton {
 2     
 3     private static Singleton singleton = new Singleton();
 4     
 5     private Singleton(){}
 6     
 7     public static Singleton getInstance(){
 8         return singleton;
 9     }
10 }

饿汉静态代码块形势

1 public class Singleton {
 2 
 3     private static Singleton singleton;
 4     static {
 5         singleton = new Singleton();
 6     }
 7     private Singleton(){}
 8 
 9     public static Singleton getInstance(){
10         return singleton;
11     }
12 }
  • 懒汉式
    • 非线程安全的实现
1 public class Singleton {
 2 
 3     private static Singleton singleton;
 4     private Singleton(){}
 5 
 6     public static Singleton getInstance(){
 7         if (singleton == null){
 8             return singleton = new Singleton();
 9         }
10         return singleton;
11     }
12 }
    • 线程安全的实现,单性能低
1 public class Singleton {
 2 
 3     private static Singleton singleton;
 4     private Singleton(){}
 5 
 6     public static synchronized Singleton getInstance(){
 7         if (singleton == null){
 8             return singleton = new Singleton();
 9         }
10         return singleton;
11     }
12 }
    • 线程安全的实现,双重校验
    • 注意:两个校验都必须加,如果第二个没有加校验,当两个线程都通过了第一个if校验,此时会有一个线程进入同步代码块,创建singleton实例,接着第二个线程也会进入同步代码块,并会在创建一个singleton。那么这样就破坏了单例。如果不加第一个if校验,那么所有的程序就会串行执行,影响执行效率。所以两个校验都必须存在
1 public class Singleton {
 2     /**由于 return singleton = new Singleton(); 这行代码在JVM中会分为三步处理
 3      * 1.给singleton分配内存空间
 4      * 2.调用singleton的构造函数开初始化
 5      * 3.将singleton对象指向分配的内存空间(这步执行了就singleton就不是null了)
 6      * 
 7      * 由于CPU会对这三个步骤重排序,如果顺序是1 3 2,那么就可能出现singleton就不是空的,但并没有初始化singleton
 8      * 这样第二个线程可能拿到的就是为初始化的singleton,所以使用volatile来修饰singleton,防止重排序的问题
 9      */
10     private static volatile Singleton singleton;
11     private Singleton(){}
12 
13     public static Singleton getInstance(){
14         if (singleton == null){
15             synchronized (Singleton.class) {
16                 if (singleton == null) {
17                     return singleton = new Singleton();
18                 }
19             }
20         }
21         return singleton;
22     }
23 }
    • 懒汉之静态内部类的方式
    • 这种方式能保证线程的安全线性,当Singleton被装载时,并不会立刻实例化静态内部类SingletonInstance,而是在需要时才会实例化
1 public class Singleton {
 2     
 3     private static class SingletonInstance{
 4         private static final Singleton singleton = new Singleton();
 5     }
 6     private Singleton(){}
 7 
 8     public static Singleton getInstance(){
 9         return SingletonInstance.singleton;
10     }
11 }
  • 枚举实现单例
    • 实现简单、线程安全、可以防止反序列化、反射的方式破坏单例模式,如果通过反序列化或反射的方式创建实例,会抛出异常。这种方式是最好的实现的方式
1 public enum Singleton{
2   INSTANCE;
3   public void whateverMethod(){
4   }    
5 }


原文链接:https://www.cnblogs.com/aaronzheng/p/12111931.html