共计 8318 个字符,预计需要花费 21 分钟才能阅读完成。
单例模式
- 定义:保障一个类仅有一个实例,并提供一个全局拜访点
- 类型:创立型
- 实用场景:想确保任何状况下都相对只有一个实例
-
长处:
- 在内存里只有一个实例,缩小了内存开销
- 能够防止对资源的多重占用
- 设置全局拜访点,严格控制拜访
- 毛病:没有接口,扩大艰难
-
重点:
- 公有结构器
- 线程平安
- 提早加载
- 序列化和反序列化平安
- 反射
- Double Check
-
动态外部类:
-
实用技能
- 反编译
- 内存原理
-
多线程 Debug
-
相干设计模式
- 单例模式和工厂模式
- 单例模式和享元模式
代码示例
懒汉式
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {}
/**
* synchronized(同步锁比拟耗费资源)* 加在静态方法上:锁的是类的 class 文件
* 加在一般办法上:锁的是堆内存中的对象
* @return
*/
public synchronized static LazySingleton getInstance(){// 懒汉式
if(lazySingleton==null){lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
public class T implements Runnable{
@Override
public void run() {LazySingleton lazySingleton = LazySingleton.getInstance();
System.out.println(Thread.currentThread()+" "+lazySingleton);
}
}
测试类:
public class Test {public static void main(String[] args) {// LazySingleton lazySingleton = LazySingleton.getInstance();
Thread t1 = new Thread(new T());
Thread t2 = new Thread(new T());
t1.start();
t2.start();
System.out.println("program end");
/* for (int i = 0; i < 10; i++) {new Thread(new T()).start();}*/
}
}
双重校验(改良):
public class LazyDoubleCheckSingleton {// volatile 多线程运行代码执行时重排序引起的问题 ( 不容许重排序)
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton;
private LazyDoubleCheckSingleton() {}
public static LazyDoubleCheckSingleton getInstance(){// 懒汉式
if(lazyDoubleCheckSingleton==null){synchronized (LazyDoubleCheckSingleton.class){if (lazyDoubleCheckSingleton==null){lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
基于类初始化的提早加载解决方案:
/**
* 基于类初始化的提早加载解决方案
*/
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() { }
private static class InnerClass{private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){return InnerClass.staticInnerClassSingleton;}
}
public class T implements Runnable{
@Override
public void run() {// LazySingleton lazySingleton = LazySingleton.getInstance();
// LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getInstance();
StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();
System.out.println(Thread.currentThread()+" "+staticInnerClassSingleton);
}
}
饿汉式
public class HungrySingleton {// 饿汉式
// 申明为 final 的变量必须在类加载时实现赋值
private static final HungrySingleton hungrySingleton;
static{hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {return hungrySingleton;}
}
序列化毁坏单例模式
public class HungrySingleton implements Serializable {// 饿汉式
// 申明为 final 的变量必须在类加载时实现赋值
private static final HungrySingleton hungrySingleton;
static{hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {}
public static HungrySingleton getInstance() {return hungrySingleton;}
/**
* 如果不写该办法,反序列化时会通过反射创立一个新的对象并返回,与序列化的对象不是同一对象。* 若写了该办法,则反序列化时,尽管通过反射创立一个新的对象,但会返回该对象。* @return
*/
private Object readResolve(){return hungrySingleton;}
}
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {HungrySingleton instance = HungrySingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
HungrySingleton newInstance = (HungrySingleton) ois.readObject();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance==newInstance);
}
}
反射攻打解决方案
public class HungrySingleton implements Serializable {// 饿汉式
// 申明为 final 的变量必须在类加载时实现赋值
private static final HungrySingleton hungrySingleton;
static{hungrySingleton = new HungrySingleton();
}
private HungrySingleton() {if (hungrySingleton!=null){throw new RuntimeException("单例结构器禁止反射调用");
}
}
public static HungrySingleton getInstance() {return hungrySingleton;}
}
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {if (InnerClass.staticInnerClassSingleton!=null){throw new RuntimeException("单例结构器禁止反射调用");
}
}
private static class InnerClass{private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){return InnerClass.staticInnerClassSingleton;}
}
public class LazySingleton {
private static LazySingleton lazySingleton;
private LazySingleton() {if (lazySingleton!=null){throw new RuntimeException("单例结构器禁止反射调用");
}
}
public synchronized static LazySingleton getInstance(){// 懒汉式
if(lazySingleton==null){lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
测试类:
/**
* 能够解决饿汉式的反射攻打,但没有解决懒汉式的反射攻打。*/
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// Class hungrySingletonClass = HungrySingleton.class;
// Class objectClass = StaticInnerClassSingleton.class;
Class objectClass = LazySingleton.class;
Constructor constructor = objectClass.getDeclaredConstructor();
constructor.setAccessible(true);
// HungrySingleton instance = HungrySingleton.getInstance();
// HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
// StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance();
LazySingleton newInstance = (LazySingleton) constructor.newInstance();
LazySingleton instance = LazySingleton.getInstance();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance==newInstance);
}
}
Enum 枚举单例
Jad:反编译工具
序列化
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// HungrySingleton instance = HungrySingleton.getInstance();
EnumInstance instance = EnumInstance.getInstance();
instance.setData(new Object());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
// HungrySingleton newInstance = (HungrySingleton) ois.readObject();
EnumInstance newInstance = (EnumInstance) ois.readObject();
System.out.println(instance.getData());
System.out.println(newInstance.getData());
System.out.println(instance.getData()==newInstance.getData());
}
}
反射
public enum EnumInstance {
INSTANCE{protected void printTest(){System.out.println("Feyl Print Test");
}
};
protected abstract void printTest();
private Object data;
public Object getData() {return data;}
public void setData(Object data) {this.data = data;}
public static EnumInstance getInstance(){return INSTANCE;}
}
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class objectClass = EnumInstance.class;
Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
EnumInstance instance = (EnumInstance) constructor.newInstance("Feyl",666);
// EnumInstance instance = EnumInstance.getInstance();
// instance.printTest();}
}
容器单例
public class ContainerSingleton {// 线程不平安
private static Map<String,Object> singletonMap = new HashMap<>();
private ContainerSingleton() {}
public static void putInstance(String key, Object instance){if (!StringUtils.isNotBlank(key)&&instance!=null){if(!singletonMap.containsKey(key)){singletonMap.put(key,instance);
}
}
}
public static Object getInstance(String key){return singletonMap.get(key);
}
}
public class T implements Runnable{
@Override
public void run() {ContainerSingleton.putInstance("object",new Object());
Object instance = ContainerSingleton.getInstance("object");
System.out.println(Thread.currentThread()+" "+instance);
}
}
测试类:
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Thread t1 = new Thread(new T());
Thread t2 = new Thread(new T());
t1.start();
t2.start();
System.out.println("program end");
}
}
TreadLocal 线程单例
public class ThreadLocalInstance {
private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance
= new ThreadLocal<ThreadLocalInstance>(){
@Override
protected ThreadLocalInstance initialValue() {return new ThreadLocalInstance();
}
};
private ThreadLocalInstance(){}
public static ThreadLocalInstance getInstance() {return threadLocalInstance.get();
}
}
public class T implements Runnable{
@Override
public void run() {ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
System.out.println(Thread.currentThread()+" "+instance);
}
}
测试类同上
“以空间换工夫”:ThreadLocal 为每一个线程创立一个空间,各个线程获取其独有的对象。
正文完