Java -- 单例设计模式

Java中单例(Singleton)模式是一种广泛使用的设计模式。单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。一些管理器和控制器常被设计成单例模式。

1,饿汉式---在类初始化时,已经自行实例化

public class Person{
     private static final Person person=new Person();
     //私有构造函数,外界无法使用
    private Person(){
    }

    //提供一个方法,获得对象
    public static Person getPerson(){
         return person;
    }
}

注:饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

缺点:饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,

2,懒汉式(线程不安全)--顾名思义,什么时候用,什么时候创建

public class Person{
    private static Person person;
    //私有构造函数
    private Person(){
    }
    public static Person getPerson(){
        if(person==null){
            person=new Person();
        }
        return person;
    }

3,懒汉式(线程安全)

public class Person{
      private static Person person=null;
      
      private Person(){
      }
      //添加 synchronized 同步锁
      public static synchronized Person getPerson(){
      if(person==null){
          person=new Person();
      }
      return person;
      }
}

注:在2.懒汉式基础上,添加同步锁,使得在多线程中可以使用。例如:当两个线程同时想创建实例,由于同一时刻只有一个线程能够得到同步锁,当第一个线程得到后第二个线程只能等待,如果没有创建该实例,就会创建。第一个线程释放同步锁以后第二个线程才能加上同步锁,执行内部代码,由于第一个线程已经创建了实例,所以第二个线程不需要重复创建。保证了多线程环境下也只有一个实例。

缺点:每次通过 getPerson() 方法得到实例的时候都会有一个试图去获取同步锁的过程,然而加锁是很耗时的,所以能避免就避免。

4,懒汉式(双重锁,线程安全)

public class Person{
      private static Person person=null;
      private Person(){
      }

      public static Person getPerson(){
            if(person==null){
                synchronized(Person.class){
                      if(person==null){
                            person=new Person();
                       }
                 }
            }
            return person;
      }
}

注:只有在person==null的时候,才需要获取同步锁,创建一次实例。当实例被创建,则无需试图加同步锁,避免3中的问题。

缺点:使用双重if判断,复杂,容易出错。

5,静态内部类(建议使用)

public class Person{
      private Person(){
      }
      /** 
        * 静态初始化器,由JVM来保证线程安全 
        */ 
      private static class SingletonPerson{
            private final static Person person=new Person();
      }

      public static Person getPerson(){
            return SingletonPerson.person;
      }
}

注:上面的SingletonPerson内部类的实例与外部类的实例没有绑定关系,只有被调用才会被加载,也就是实现了延时加载。即按需创建实例。

你可能感兴趣的:(Java -- 单例设计模式)