单例模式,每个程序员在开发中都需要用到的设计模式,也是所有设计模式中最简单,应用最多的。单例模式根据创建的单例的时机可以分为饿汉、懒汉两种;根据创建方式又可以分为静态内部类单例、枚举单例两种。
1.饿汉单例模式
public class Person{
private static Person person=new Person();//创建一个私有的静态对象
private Person(){//构造方法私有化,不能随意通过new的方式获得其对象
}
public static Person getPerson(){//向外暴露出一个方法,可以通过这个方法获得一个静态对象,并且这个静态对象不管这个类是否被调用过都已经存在
return person;
}
}
以上代码就是一个简单的饿汉单例模式,饿汉单例通过构造方法私有化使得不能随意创建对象,只能通过它提供的getPerson()方法来获得Person的静态对象,而且这个静态对象,不论你是否调用它的getPerson()方法,都已经存在。
2.懒汉单例模式
public class Person{
private static Person person;//创建一个私有的静态对象,但不实例化
private Person(){//构造方法私有化
}
public static synchronized Person getInstance(){//同步方法,保证多线程时也只会有一个person对象
if(person==null){//只有第一次调用的时候后实例化一个person对象
return person=new Person();
}
return person;
}
}
以上代码就是一个简单的懒汉单例模式,饿汉、懒汉的区别就在于对象实例化的时机,懒汉模式时只有调用过getInstance()方法,Person对象才会被实例化,也只会实例化一次,并且进行了同步处理,保证了多线程时,也只会有一个person对象,但是这样就造成了懒汉模式每次被调用的时候都会同步,造成了资源浪费。
还有一种双重检查锁定单例模式(DCL),但是这种方法不建议使用,这种方法虽然在一定程度上确保了对象的唯一性,也在一定程度上解决了资源消耗,多余同步,线程安全等问题,但还是存在某些情况下会失效的问题。代码我就不写了,有兴趣的可以自己去百度看看。
3.静态内部类单例模式
因为懒汉模式和双重检查锁定单例模式都有一定的缺点,不建议使用,而饿汉模式也存在内存资源浪费的问题,所以才有了静态内部类单例模式。静态内部类单例不仅保证了线程安全,实例对象的唯一性,而且也起到了延迟创建实例的作用。
public class Person{
private Person(){//私有化构造方法
}
public static Person getInstance(){//调用此方法是通过静态内部类创建person实例,保证线程安全和实例的唯一性,并实现了延迟创建实例
reyurn PersonHolder.person;
}
private static class PersonHolder{
private static final Person person=new Person();
}
}
当一次加载person类的时候并不会直接创建person的实例,而是在第一次调用getInstance()方法时,加载PersonHolder类来创建Person的实例,这种方法既保证了线程安全和实例唯一,又起到了延迟创建实例的作用,所以推荐使用这种方法.
4.枚举单例模式
public enum Person{
INSTANCE;
}
看到枚举单例的代码是不是好简单,写法简单是枚举单例的最大优点,而且枚举默认是线程安全的,并且在任何情况下都是一个单例.
5.总结
系统的学习了下单例模式,虽然以前也实际使用过,但是从没总结过,借着这次机会系统的学习总结一下,本人来讲,比较推荐第三种方法实现单例模式,虽然第三种也会有一定的问题,就是在序列化\反序列化时会默认生成新的实例,但是在实际项目应用中这种情况很少发生.当然,单例模式不是只有这几种实现方式,还有利用容器实现单例等方法,喜欢的可以去了解下,本人还是喜欢用第三种.