什么是单例模式?
保证整个程序中只有一个类的实例叫做单例模式
饿汉式
饿汉式
package hungry;
/**
* 饿汉式
* 优点:效率高,线程安全
* 缺点:有可能浪费空间
*/
public class HungrySingleton {
private static HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton get(){
return hungrySingleton;
}
}
饿汉式 - 静态代码块
package hungry;
public class HungryStaticSingleton {
private static HungryStaticSingleton hungryStaticSingleton;
private HungryStaticSingleton() {
}
static {
hungryStaticSingleton = new HungryStaticSingleton();
}
public static HungryStaticSingleton get(){
return hungryStaticSingleton;
}
}
懒汉式
懒汉式
package lazy;
/**
* 懒汉式
* 优点:节省空间,线程安全
* 缺点:效率太慢
*/
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton() {
}
public synchronized static LazySingleton get(){
if(null == lazySingleton){
return new LazySingleton();
}
return lazySingleton;
}
}
懒汉式 - 双重检查锁
package lazy;
/**
* 懒汉式 - 双重检查锁
* 优点:线程安全,节省空间
* 缺点:代码可读性差
*/
public class LazyDoubleCheckSingleton {
private static volatile LazyDoubleCheckSingleton lazySingleton = null;
private LazyDoubleCheckSingleton() {
}
public static LazyDoubleCheckSingleton get(){
// 校验是否加锁
if(null == lazySingleton){
synchronized (LazyDoubleCheckSingleton.class){
// 校验是否可以实例化
if(null == lazySingleton){
lazySingleton = new LazyDoubleCheckSingleton();
// 有指令重排序问题
// lazySingleton = new LazyDoubleCheckSingleton(); 这行代码 在JVM底层有三个操作
// 1、开辟空间
// 2、对象实例化new
// 3、指针指向
}
}
}
return lazySingleton;
}
}
懒汉式 - 内部类
package lazy;
/**
* 懒汉式 - 内部类
* 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
* 缺点:可读性又变差了
*/
public class LazyStaticInnerClassSingleton {
private LazyStaticInnerClassSingleton(){
if(LazyHolder.instance != null){
throw new RuntimeException("非法访问");
}
}
public static LazyStaticInnerClassSingleton get(){
return LazyHolder.instance;
}
private static class LazyHolder{
private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
}
}
注册式
注册式 - 枚举
package register;
/**
* 注册式 - 枚举类
* 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
* 缺点:如果枚举类多的话,浪费内存
*/
public enum EnumSingleton {
INSTANCE;
public static EnumSingleton get(){
return INSTANCE;
}
}
注册式 - 容器
package register;
import java.util.HashMap;
import java.util.Map;
/**
* 注册式 - 容器类
* 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
* 缺点:可以被反序列化破坏
*/
public class ContainerSingleton {
private ContainerSingleton(){
}
private static volatile Map<String, Object> ioc = new HashMap<>();
public static Object get(String className) throws Exception {
if(!ioc.containsKey(className)){
synchronized (ContainerSingleton.class){
if(!ioc.containsKey(className)){
Object o = Class.forName(className).newInstance();
ioc.put(className, o);
return ioc.get(className);
}else{
return ioc.get(className);
}
}
}else {
return ioc.get(className);
}
}
}
package register;
import java.io.Serializable;
public class User {
}
ThreadLocal式
ThreadLocal式
package threadlocal;
public class ThreadLocalSingleton {
private ThreadLocalSingleton(){
}
private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
public static ThreadLocalSingleton get(){
return threadLocal.get();
}
}
问题
反射
被反射破坏
package lazy;
/**
* 懒汉式 - 内部类
* 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
* 缺点:可读性又变差了
*/
public class LazyStaticInnerClassSingleton {
private LazyStaticInnerClassSingleton(){
}
public static LazyStaticInnerClassSingleton get(){
return LazyHolder.instance;
}
private static class LazyHolder{
private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
}
}
package lazy;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
LazyStaticInnerClassSingleton l = LazyStaticInnerClassSingleton.get();
System.out.println(l);
Class<LazyStaticInnerClassSingleton> clazz = LazyStaticInnerClassSingleton.class;
Constructor<LazyStaticInnerClassSingleton> declaredConstructor = clazz.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyStaticInnerClassSingleton lazyStaticInnerClassSingleton = declaredConstructor.newInstance();
System.out.println(lazyStaticInnerClassSingleton);
}
}
防止被反射破坏
package lazy;
/**
* 懒汉式 - 内部类
* 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
* 缺点:可读性又变差了
*/
public class LazyStaticInnerClassSingleton {
private LazyStaticInnerClassSingleton(){
if(LazyHolder.instance != null){
throw new RuntimeException("非法访问");
}
}
public static LazyStaticInnerClassSingleton get(){
return LazyHolder.instance;
}
private static class LazyHolder{
private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
}
}
反序列化
被反序列化破坏
package register;
import java.util.HashMap;
import java.util.Map;
/**
* 注册式 - 容器类
* 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
* 缺点:可以被反序列化破坏
*/
public class ContainerSingleton {
private ContainerSingleton(){
}
private static volatile Map<String, Object> ioc = new HashMap<>();
public static Object get(String className) throws Exception {
if(!ioc.containsKey(className)){
synchronized (ContainerSingleton.class){
if(!ioc.containsKey(className)){
Object o = Class.forName(className).newInstance();
ioc.put(className, o);
return ioc.get(className);
}else{
return ioc.get(className);
}
}
}else {
return ioc.get(className);
}
}
}
package register;
import java.io.Serializable;
public class User implements Serializable {
}
package register;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
User u1 = (User) ContainerSingleton.get("register.User");
// 序列化 内存中的Java对象 -> 磁盘
// 反序列化 磁盘 —> 内存中的Java对象
// 序列化
FileOutputStream fileOutputStream = new FileOutputStream("obj.user");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(u1);
fileOutputStream.close();
objectOutputStream.close();
// 反序列化
FileInputStream fileInputStream = new FileInputStream("obj.user");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
User u2 = (User) objectInputStream.readObject();
fileInputStream.close();
objectInputStream.close();
System.out.println(u1);
System.out.println(u2);
}
}
防止被反序列化破坏
package register;
import java.io.Serializable;
public class User implements Serializable {
private Object readResolve() throws Exception {
return ContainerSingleton.get("register.User");
}
}
总结
只有注册式 - 枚举不会被反射破坏和反序列化破坏,其余都会