1什么是单例模式:
单例模式就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类
单例模式有三种:
①懒汉式模式
//懒汉式单例
public class SingleTon {
private static SingleTon singleTon;
private SingleTon(){}
public static SingleTon getInstance(){
if(singleTon==null){
singleTon=new SingleTon();
}
return singleTon;
}
}
优点:第一次调用才初始化,避免内存的浪费
缺点:线程不安全,如果多个线程同时调用,可能会产生多个单例对象
②懒汉式同步锁
public class SingleTon {
private static SingleTon singleTon;
private SingleTon(){}
public static synchronized SingleTon getInstance(){
if(singleTon==null){
singleTon=new SingleTon();
}
return singleTon;
}
}
在上面的基础上确保了线程安全
③双重校验锁
用懒汉式同步锁可以解决线程安全问题,但是我们在获得单例对象时有必要每次都判断线程同步锁吗?如果单例对象已经不为空了,我们直接返回单例对象就行了,就不需要判断线程同步锁和构造单例对象了,双重校验锁是在懒汉式同步锁的基础上再加上一层单例对象是否为空的判断,以减少判断线程同步锁的次数,从而提高效率,代码如下:
public class SingleTonFour {
private volatile static SingleTonFour singleTonFour = null; // 加上volatile关键字,线程每次使用到被volatile关键字修饰的变量时,都会去堆里拿最新的数据
private SingleTonFour() {
}
public static SingleTonFour getInstance() {
if (singleTonFour == null) { // 在懒汉式同步锁的基础上加上了一个判断,如果单例对象不为空,就不需要执行获得对象同步锁的代码,从而提高效率
synchronized (SingleTonFour.class) { // 只有当单例对象为空时才会执行
if (singleTonFour == null) {
singleTonFour = new SingleTonFour();
}
}
}
return singleTonFour;
}
}
优点:懒加载,线程安全,效率高
缺点:代码复杂
④饿汉式单例
public class SingleTon {
private static final SingleTon SINGLE_TON=new SingleTon();
private SingleTon(){}
public static SingleTon getInstance(){
return SINGLE_TON;
}
}
优点:不用加锁,执行效率提高,适用类对象功能简单,占用内存较小,使用频繁
缺点:类加载时就初始化,浪费内存,不适用类对象功能复杂,占用内存大,使用概率低
⑤登记式模式(holder)
java的静态内部类的加载是在使用到该静态内部类的时候才去加载的,并且加载静态内部类是线程安全的,我们可以利用这一特性来定义单例模式,具体代码如下:
public class SingleTonFive {
/**
* 私有静态内部类,程序只有当使用到静态内部类是才会去加载静态内部类,然后生成单例对象
*/
private static class SingleTonFiveHolder {
public static SingleTonFive singleTonFive = new SingleTonFive();
}
private SingleTonFive() {
}
/**
* 只用调用了getInstance方法,程序中使用到了静态内部类SingleTonFiveHolder,才会去加载SingleTonFiveHolder,生成单例对象
* @return
*/
public SingleTonFive getInstance() {
return SingleTonFiveHolder.singleTonFive;
}
}
优点:实现简单,懒加载,线程安全
缺点:增加了一个静态内部类,apk文件增大
⑥枚举
/**
* 枚举单例模式
* 优点:线程安全,不用担心序列化和反射问题
* 缺点:枚举占用的内存会多一点,内部占用内存比静态变量多得多
*/
public enum SingleTonSix {
INSTANCE;
private String field;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
单例模式的定义有饿汉式、懒汉式、懒汉式同步锁、双重校验锁、静态内部类、枚举这几种定义方式,每种方式都有他们优缺点,我们可以根据自己的需要去选择自己的定义方式。