单例模式
- 定义:保证一个类仅有一个实例,并提供一个全局访问的点。
- 适用场景:任何情况下都绝对只有一个实例。
- 优点:减少内存开销、避免对资源的多重占用、设置全局访问点,严格控制访问
- 缺点:没有接口,扩展困难。
单例模式下记得 添加私有构造器,防止被外部方法直接new创建。
懒汉模式(线程不安全)
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){}
/**
* 有线程安全问题,需要添加synchronized
* @return
*/
public synchronized static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
DoubleCheck 双重检查
只在第一次初始化时加锁,提高效率。使用volatile消除重排序的隐患。(初始化类和给本地绑定引用,如果先绑定引用,还未初始化完成,其他线程进来,获取到值会直接报错。)
public class DoubleCheckLazySingleton {
private volatile static DoubleCheckLazySingleton lazySingleton = null;
private DoubleCheckLazySingleton(){}
public static DoubleCheckLazySingleton getInstance(){
if(lazySingleton == null){
synchronized (DoubleCheckLazySingleton.class){
if(lazySingleton == null){
lazySingleton = new DoubleCheckLazySingleton();
}
}
}
return lazySingleton;
}
}
静态内部类
public class StaticInnerSing {
private static class InnerClass{
private static StaticInnerSing staticInnerSing = new StaticInnerSing();
}
public static StaticInnerSing getInstance(){
return InnerClass.staticInnerSing;
}
}
饿汉式
public class HungraySingleton {
private HungraySingleton(){};
private final static HungraySingleton hungraySingleton = new HungraySingleton();
public static HungraySingleton getInstance(){
return hungraySingleton;
}
}
解决序列化 破环单例模式原则
把单例类写入文件,读取出来和原来的不是同一个对象。
重写readResolve方法,可以使原则不被破坏
public static void main(String[] args) throws IOException, ClassNotFoundException {
HungraySingleton singleton = HungraySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("single_file"));
oos.writeObject(singleton);
File file = new File("single_file");
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
HungraySingleton otherSingleton = (HungraySingleton)oin.readObject();
System.out.println(singleton);
System.out.println(otherSingleton);
System.out.println(singleton == otherSingleton);
}
public class HungraySingleton implements Serializable{
private HungraySingleton(){};
private final static HungraySingleton hungraySingleton = new HungraySingleton();
public static HungraySingleton getInstance(){
return hungraySingleton;
}
private Object readResolve(){
return hungraySingleton;
}
反射攻击的解决方案(在私有构造方法内加判断)
public class HungraySingleton implements Serializable{
private final static HungraySingleton hungraySingleton = new HungraySingleton();
private HungraySingleton(){
if(hungraySingleton != null){
throw new RuntimeException("单例不允许反射构建!!");
}
}
public static HungraySingleton getInstance(){
return hungraySingleton;
}
private Object readResolve(){
return hungraySingleton;
}
枚举单例(最推荐的一种方式)
public enum EnumSingleton {
DATASOURCE;
private EnumModule module = null;
private EnumSingleton(){
module = new EnumModule();
}
public EnumModule getInstance(){
return module;
}
public static class EnumModule{}
}
通过threadLocal每个线程获取自己的单例
public class ThreadLocalInstance {
private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance
= new ThreadLocal<ThreadLocalInstance>(){
protected ThreadLocalInstance initialvalue(){
return new ThreadLocalInstance();
}
};
private ThreadLocalInstance(){}
public static ThreadLocalInstance getInstance(){
return threadLocalInstance.get();
}
}
原型模式
定义:原型实例指定创建对象种类,通过拷贝这些原型创建新的对象。不需要知道任何创建细节,不调用构造函数。
适用场景:类初始化消耗资源多,new产生的对象需要非常繁琐的过程。构造函数比较复杂,循环体中产生大量对象。
优点:比直接new性能高,简化创建过程。
缺点:必须配备克隆方法。深拷贝、浅拷贝要运用得当。
原型模式会破坏单例
浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
深拷贝
public Object clone() {
Date d = null;
try {
d = (Date)super.clone();
if (cdate != null) {
d.cdate = (BaseCalendar.Date) cdate.clone();
}
} catch (CloneNotSupportedException e) {}
return d;
}