首先要肯定这是两个单列模式。 懒汉式和饿汉式主要区别是建立单列对象的时间不一样。 懒汉式:之因此叫作懒汉式,是由于只有在须要的时候才会建立单列对象安全
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.以本身实例为返回值的公有静态方法排序