单例模式:创建型模式。
单例单例,顾名思义,只有一个例子可用。所以构造函数一定是私有的,且类中会实例一个自己的对象instance。
实际使用过程中,通过调用getInstance方法获取并使用这唯一的实例,不需要实例化该对象。
1 懒汉模式
懒汉就是突出一个懒,没有真正使用就不会有行动(也就是不会创建所谓的单例)。什么时候你要用了,再实例化。
懒汉模式又分多种情况:
①线程不安全
当单例还没创建,多个线程要使用此类就可能造成多次实例化。多线程并发不安全。
public class Pattern01_LazyAndUnsafe { private static Pattern01_LazyAndUnsafe instance; private Pattern01_LazyAndUnsafe(){ } public static Pattern01_LazyAndUnsafe getInstance(){ if (instance==null){ instance = new Pattern01_LazyAndUnsafe(); } return instance; }
}
②线程安全
为获取单例的方法上锁后,当单例还没创建,多个线程要使用此类就需要等待第一个线程调用方法完毕后一次调用。保证了并发的安全性。
public class Pattern02_LazyAndSafe { private static Pattern02_LazyAndSafe instance; private Pattern02_LazyAndSafe(){ } public static synchronized Pattern02_LazyAndSafe getInstance(){ if (instance==null){ instance = new Pattern02_LazyAndSafe(); } return instance; }
}
③双检锁模式
在这里,并没有对方法直接上锁,所以多线程并发时,可以同时调用获取实例的方法。而只有当你还没有实例化时,对将要进行实例化的代码块上锁。
避免了已实例化还会线程堵塞的情况。
public class Pattern04_DoubleLocking { private static volatile Pattern04_DoubleLocking instance; private Pattern04_DoubleLocking(){ } //不会因为类没被实例而线程堵塞 public static Pattern04_DoubleLocking getInstance(){ if (instance == null){ //当单例还不存在时,多个线程在getInstance方法中堵塞 synchronized (Pattern04_DoubleLocking.class){ if (instance == null){ instance = new Pattern04_DoubleLocking(); } } } return instance; } }
④内部类模式
此模式在类中定义了内部类,对实例用final修饰,只能实例化一次,线程安全且也有懒汉特性。
同双检锁模式一样,避免了实例化后的线程堵塞。
public class Pattern05_Holder { private static class Pattern05_HolderInner{ private static final Pattern05_Holder instance = new Pattern05_Holder(); } private Pattern05_Holder(){ } public static final Pattern05_Holder getInstance(){ return Pattern05_HolderInner.instance; } }
2 饿汉模式
同懒汉模式相反,不管用不用,单例已经提前创建完毕。直接获取即可。
直接避免了线程不安全问题,但是可能存在资源浪费。
public class Pattern03_Hungry { private static Pattern03_Hungry instance = new Pattern03_Hungry(); private Pattern03_Hungry(){ } public static Pattern03_Hungry getInstance(){ return instance; } }
3 枚举模式
因为其支持序列化机制,所以适用于反序列化创建对象。
同饿汉模式,会提前实例化。
//枚举模式(用于反序列化创建对象) public enum Pattern06_Enum { INSTANCE; }