懒汉式和饿汉式

首先要肯定这是两个单列模式。 懒汉式和饿汉式主要区别是建立单列对象的时间不一样。 懒汉式:之因此叫作懒汉式,是由于只有在须要的时候才会建立单列对象安全

public class Singleton{ 
    private Singleton(){}//要有构造方法
    private static Singleton singleton = null;  //不创建对象,可是要静态修饰
    public static synchronized Singleton getInstance(){
             if(singleton == null) {        //先判断是否为空,若是为空则直接返回。                
                 singleton = new Singleton ();  //懒汉式作法 
             }
             return singleton ;
     }
}

饿汉式:无论你何时用,在类建立的时候就已经穿件该实例多线程

public class Singleton{ 
    public Singleton(){}
    private static Singleton singleton = new Singleton();  //创建对象,静态变量
    public static Singleton getInstance(){
        return singleton ;//直接返回单例对象    }}

单列的三个基本点: 1.必须有私有的构造方法。 2.指向本身私有的静态实例变量。 3.以本身私有实例为返回值的公开静态方法。函数

有关线程安全的单例。有一下几种方法: 1.借助内部类性能

public class Singleton {
    
   private Singleton() { }//私有构造方法
 
   private static class SingletonHolder {//内部类
      private final static Singleton INSTANCE = new Singleton();
   }
 
   public static Singleton getInstance() {
      return SingletonHolder.INSTANCE;
   }
}
 
属于懒汉式单例,由于Java机制规定,**内部类SingletonHolder只有在getInstance()方法第一次调用的时候才会被加载(实现了lazy)**,并且其加载过程是线程安全的。内部类加载的时候实例化一次instance。

2.使用同步方法(懒汉式)线程

public class Singleton {  //建立类
      private static Singleton instance;  //建立一个静态变量,可是该变量没有被赋值,也就是没有实例化
       private Singleton (){//私有构造方法
          
      }   
       public static synchronized Singleton getInstance(){    //对获取实例的方法进行同步
         if (instance == null)     //若是该变量没有被实例化
           instance = new Singleton(); //直接实例化
         return instance;//返回已经实例化的变量
      }
  }

该方法,一次锁住了一个方法,保证了线程安全。缺点:同步的颗粒度有点大。 每一个synchronized方法都必须得到调用该方法的实例的锁方能执行,不然所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能得到该锁,从新进入可执行状态。这种机制确保同一时刻对于每个实例,其所声明为synchronized的成员函数中至多只有一个处于可执行的状态(由于至多只有一个可以得到该实例对应的锁),从而有效的避免了类成员变量的访问冲突。 也就是该方法不能同时被屡次,只能一个调用完后,另外一个才能调用。日志

3.双重检测方案:code

public class Singleton {
   private static Singleton instance = null;//静态变量
 
   private Singleton() { }//私有构造方法
 
   public static Singleton getInstance() {
      if(instance == null) {
         synchronzied(Singleton.class) {//同步代码块
            Singleton temp = instance;//将静态变量赋值给一个临时变量
            if(temp == null) {
               temp = new Singleton();//若是临时变量为空,则实例化
               instance = temp//用临时变量给静态变量赋值
            }
         }
      }
 
      return instance;
   }
}
//为什幺引出一个临时变量,有何意义?
//引入一个临时变量,是同步代码块中存在一个数据依赖性。所以能够避免多线程之间的问题。该代码是先读后写,再赋值
//单线程执行的时候,虽然会指令重排序,可是因为存在数据依赖性。并不会影响代码的执行结果
//可是多线程执行的时候,线程与线程之间不存在数据依赖性,所以指令重排序会影响到程序运行的结果
 
_因为指令重排序问题,因此不能够直接写成下面这样:_
public class Singleton {
   private static Singleton instance = null;
 
   private Singleton() { }
 
   public static Singleton getInstance() {
      if(instance == null) {
         synchronzied(Singleton.class) {
            if(instance == null) {
               instance = new Singleton();
            }
         }
      }
 
      return instance;
   }
}
//也就是说代码并非彻底按照咱们所写的顺序一个个的取执行,所以该方法不可行。 

可是若是instance实例变量用volatile修饰就能够了,volatile修饰的话就能够确保instance = new Singleton();对应的指令不会重排序,以下的单例代码也是线程安全的:
public class Singleton {
   private static volatile Singleton instance = null;
 
   private Singleton() { }
 
   public static Singleton getInstance() {
      if(instance == null) {
         synchronzied(Singleton.class) {
            if(instance == null) {
               instance = new Singleton();
            }
         }
      }
 
      return instance;
   }
}

//之因此使用volatile修饰变量后可使用该方法,是由于volatile能够禁止指令重排序,所以,使用volatile修饰,可使用该方法对象

单例模式应用的场景通常发如今如下条件下:   (1)资源共享的状况下,避免因为资源操做时致使的性能或损耗等。如上述中的日志文件,应用配置。   (2)控制资源的状况下,方便资源之间的互相通讯。如线程池等。 单例模式要素: a.私有构造方法 b.私有静态引用指向本身实例 c.以本身实例为返回值的公有静态方法排序

相关文章
相关标签/搜索