简介
- 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式的写法
饿汉模式
- 线程安全,通过JVM的类加载机制保证其只会有一个实例。
- 写法示例
package designpattren.hungrysingleton;
public class HungrySingletonTest {
public static void main(String[] args) {
HungrySingleton instance = HungrySingleton.getInstance();
HungrySingleton instance1 = HungrySingleton.getInstance();
System.out.println(instance == instance1);
}
}
class HungrySingleton{
private static HungrySingleton instance =new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return instance;
}
}
懒汉模式
- 线程不安全,用volatile关键字,防止JIT进行指令重排,导致的空指针问题,使得其可以在多线程环境下使用。
- 写法示例
package designpattren.lazysingleton;
public class LazySingletonTest {
public static void main(String[] args) {
new Thread(()->{
LazySingleTon instance =LazySingleTon.getInstance();
System.out.println(instance);
}).start();
new Thread(()->{
LazySingleTon instance =LazySingleTon.getInstance();
System.out.println(instance);
}).start();
}
}
class LazySingleTon{
private volatile static LazySingleTon instance;
private LazySingleTon(){
}
public static LazySingleTon getInstance(){
if (instance ==null){
synchronized (LazySingleTon.class){
if(instance==null){
instance = new LazySingleTon();
}
}
}
return instance;
}
}
静态内部类单例模式
- 线程安全,通过静态内部类实现单例,同样依赖JVM的类加载机制保证它的线程安全。
- 写法示例
package designpattren.innerclasssingleton;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class InnerClassSingletonTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException, ClassNotFoundException {
InnerClassSingleton instance = InnerClassSingleton.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("testSerializable"));
oos.writeObject(instance);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("testSerializable"));
Object object =(InnerClassSingleton)ois.readObject();
System.out.println(instance == object);
}
}
class InnerClassSingleton implements Serializable {
static final long serialVersionUID = 42L;
private static class InnerClassHolder{
private static InnerClassSingleton instance = new InnerClassSingleton();
}
private InnerClassSingleton(){
if(InnerClassHolder.instance!=null){
throw new RuntimeException("单例不允许多个实例");
}
}
public static InnerClassSingleton getInstance(){
return InnerClassHolder.instance;
}
Object readResolve() throws ObjectStreamException{
return InnerClassHolder.instance;
}
}
枚举单例模式
- 使用枚举实现的单例模式也是线程安全的,写法也比较简单,缺点是可读性比较低。
- 这种方式下,也可以防止序列化攻击。
- 写法示例
package designpattren.enumsingleton;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
public enum EnumSingleton{
INSTANCE;
public void print(){
System.out.println(this.hashCode());
}
}
class EnumTest{
public static void main(String[] args) throws Exception {
EnumSingleton instance = EnumSingleton.INSTANCE;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test EnumSingleton"));
Object object =( EnumSingleton)ois.readObject();
System.out.println(object == instance);
}
}