设计模式之单例模式
单例模式
保证该类只有一个实例,并提供一个全局访问点
懒汉模式
懒汉模式是指该单例模式不会提前创建实例,只有外部调用时才会创建一个实例,好处是 如果使用不到就不会占用内存资源
非线程安全
/**
* 懒汉模式1,私有化构造器,私有静态变量,提供一个全局访问方法
*
* @author leo.z.l
* @create 2019-11-27 15:31
*/
public class LazyInitializationSingleton {
private static LazyInitializationSingleton instance;
private LazyInitializationSingleton() {
}
public static LazyInitializationSingleton getInstance() {
if (instance == null) {
instance = new LazyInitializationSingleton();
}
return instance;
}
}
线程安全
/**
* 懒汉式:线程安全的单例模式
* @author leo.z.l
* @create 2019-11-27 15:44
*/
public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;
private ThreadSafeSingleton() {
}
/**
* 在方法级加锁,以保证线程安全
* @return
*/
public static synchronized ThreadSafeSingleton getInstance(){
if (instance == null) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}
DCL
/**
* 懒汉式:线程安全的双重检查锁单例模式
*
* @author leo.z.l
* @create 2019-11-27 15:49
*/
public class DoubleCheckLazyInitializationSingleton {
private static DoubleCheckLazyInitializationSingleton instance;
private DoubleCheckLazyInitializationSingleton() {
}
/**
* 没有在方法级上加锁,而是在内部加锁,提高了效率
* @return
*/
public static DoubleCheckLazyInitializationSingleton getInstance() {
if (instance == null) {
synchronized (String.class) {
if (instance == null) {
instance = new DoubleCheckLazyInitializationSingleton();
}
}
}
return instance;
}
}
静态内部类
effective java 第二版时推荐使用此种方式创建单例,当然,现在也可以使用此种方式创建单例,毕竟枚举不常使用
/**
* 静态内部类创建单例,缺陷是通过反序列化的方式可以创建多个实例
* @author leo.z.l
* @create 2019-11-27 16:27
*/
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {
}
/**
* 使用内部类辅助创建单例,使用final修饰,一旦创建不可更改
*/
private static class SingletonHelper{
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){
return SingletonHelper.INSTANCE;
}
}
饿汉模式
实例在类初始化时就已经创建,如果没有使用,会占用内存资源
枚举单例
- 在EffectiveJava一书第三版中,推荐使用该方式创建单例模式
- 枚举类继承了 java.lang.Enum 其中实现了 Comparable, Serializable
- Enum中阻止了默认的序列化方式,则通过传统的序列化方式不会破坏单例模式
/**
* 单例模式是提供了序列化安全,
*
* @author leo.z.l
* @create 2019-11-27 15:55
*/
public enum EnumSingleton {
/**
* 单一的枚举值即为一个单例模式
*/
SINGLETON;
}
反编译文件
public final class cn.leo.singleton.EnumSingleton extends java.lang.Enum<cn.leo.singleton.EnumSingleton> {
public static final cn.leo.singleton.EnumSingleton SINGLETON;
private static final cn.leo.singleton.EnumSingleton[] $VALUES;
public static cn.leo.singleton.EnumSingleton[] values();
public static cn.leo.singleton.EnumSingleton valueOf(java.lang.String);
private cn.leo.singleton.EnumSingleton();
static {};
}
普通饿汉模式
/**
* 普通的饿汉模式
*
* @author leo.z.l
* @create 2019-11-27 16:08
*/
public class EagerInitialization {
private static EagerInitialization instance = new EagerInitialization();
private EagerInitialization() {
}
public static EagerInitialization getInstance(){
return instance;
}
}
静态代码块模式
/**
* 通过静态代码块进行初始化
*
* @author leo.z.l
* @create 2019-11-27 16:13
*/
public class StaticBlockSingleton {
private static StaticBlockSingleton instance;
static {
try {
instance = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("初始化时异常");
}
}
private StaticBlockSingleton() {
}
public static StaticBlockSingleton getInstance() {
return instance;
}
}
破坏单例模式
除了枚举实现的单例模式外,其他的方式都有bug,可以通过反射和序列化的方式创建多个实例
反射的方式
/**
* 使用反射的方式可以创建多个实例 -- 枚举除外
*
* @author leo.z.l
* @create 2019-11-27 16:32
*/
public class ReflectionSingletonTest {
@Test
public void doubleCheckLazyInitializationSingletonTest() {
DoubleCheckLazyInitializationSingleton instanceOne = DoubleCheckLazyInitializationSingleton.getInstance();
DoubleCheckLazyInitializationSingleton instanceTwo = null;
try {
Constructor[] constructors = DoubleCheckLazyInitializationSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (DoubleCheckLazyInitializationSingleton) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("doubleCheckLazyInitializationSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void eagerInitializationTest() {
EagerInitialization instanceOne = EagerInitialization.getInstance();
EagerInitialization instanceTwo = null;
try {
Constructor[] constructors = EagerInitialization.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (EagerInitialization) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("eagerInitializationTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void enumSingletonTest() {
EnumSingleton instanceOne = EnumSingleton.SINGLETON;
EnumSingleton instanceTwo = null;
try {
Constructor[] constructors = EnumSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (EnumSingleton) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("enumSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void lazyInitializationSingletonTest() {
LazyInitializationSingleton instanceOne = LazyInitializationSingleton.getInstance();
LazyInitializationSingleton instanceTwo = null;
try {
Constructor[] constructors = LazyInitializationSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (LazyInitializationSingleton) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("lazyInitializationSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void staticBlockSingletonTest() {
StaticBlockSingleton instanceOne = StaticBlockSingleton.getInstance();
StaticBlockSingleton instanceTwo = null;
try {
Constructor[] constructors = StaticBlockSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (StaticBlockSingleton) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("staticBlockSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void staticInnerClassSingletonTest() {
StaticInnerClassSingleton instanceOne = StaticInnerClassSingleton.getInstance();
StaticInnerClassSingleton instanceTwo = null;
try {
Constructor[] constructors = StaticInnerClassSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (StaticInnerClassSingleton) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("staticInnerClassSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void threadSafeSingletonTest() {
ThreadSafeSingleton instanceOne = ThreadSafeSingleton.getInstance();
ThreadSafeSingleton instanceTwo = null;
try {
Constructor[] constructors = ThreadSafeSingleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
//Below code will destroy the singleton pattern
constructor.setAccessible(true);
instanceTwo = (ThreadSafeSingleton) constructor.newInstance();
break;
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
System.out.println("threadSafeSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
}
反序列化的方式
/**
* 使用反序列化的方式可以创建多个实例 -- 枚举除外
*
* @author leo.z.l
* @create 2019-11-27 16:32
*/
public class SerializedSingletonTest {
@Test
public void doubleCheckLazyInitializationSingletonTest() {
try {
DoubleCheckLazyInitializationSingleton instanceOne = DoubleCheckLazyInitializationSingleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
DoubleCheckLazyInitializationSingleton instanceTwo = (DoubleCheckLazyInitializationSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("doubleCheckLazyInitializationSingletonTest============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void eagerInitializationTest() {
try {
EagerInitialization instanceOne = EagerInitialization.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
EagerInitialization instanceTwo = (EagerInitialization) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("EagerInitialization============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void enumSingletonTest() {
try {
EnumSingleton instanceOne = EnumSingleton.SINGLETON;
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
EnumSingleton instanceTwo = (EnumSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("EnumSingleton============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void lazyInitializationSingletonTest() {
try {
LazyInitializationSingleton instanceOne = LazyInitializationSingleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
LazyInitializationSingleton instanceTwo = (LazyInitializationSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("LazyInitializationSingleton============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void staticBlockSingletonTest() {
try {
StaticBlockSingleton instanceOne = StaticBlockSingleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
StaticBlockSingleton instanceTwo = (StaticBlockSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("StaticBlockSingleton============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void staticInnerClassSingletonTest() {
try {
StaticInnerClassSingleton instanceOne = StaticInnerClassSingleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
StaticInnerClassSingleton instanceTwo = (StaticInnerClassSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("StaticInnerClassSingleton============");
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void threadSafeSingletonTest() {
try {
ThreadSafeSingleton instanceOne = ThreadSafeSingleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
out.close();
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
ThreadSafeSingleton instanceTwo = (ThreadSafeSingleton) in.readObject();
in.close();
System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
System.out.println("ThreadSafeSingleton============");
} catch (Exception e) {
e.printStackTrace();
}
}
}
第一要有志,第二要有识,第三要有恒。