终结23种设计模式-单列模式
1 单列模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
1 饿汉式
public class HungryManSingle { private static HungryManSingle hungryManSingle=new HungryManSingle(); //构造方法私有 private HungryManSingle(){} public static HungryManSingle getHungryManSingle(){ return hungryManSingle; } }
写出来之后:面试官问,为什么这个是线程安全的。
在线程访问单例对象之前就已经创建好了。再加上,由于一个类在整个生命周期中只会被加载一次,因此该单例类只会创建一个实例。也就是说,线程每次都只能也必定只可以拿到这个唯一的对象。即饿汉式单例天生就是线程安全的。
饿汉式是当满足类加载条件的时候就在类加载过程中的初始化环节就完成了实例的创建(借此保证线程安全,即其他线程不会访问到还未初始化完毕的实例),因为类加载过程JVM会自动加锁,因此保证了单例特性。
2 懒汉式:线程不安全
public class LazySingleObjectNoSyn { private static LazySingleObjectNoSyn lazySingleObjectNoSyn; private LazySingleObjectNoSyn(){} public static LazySingleObjectNoSyn getLazySingleObjectNoSyn(){ if(lazySingleObjectNoSyn ==null){ lazySingleObjectNoSyn = new LazySingleObjectNoSyn(); } return lazySingleObjectNoSyn; } }
写出来之后:面试官问,这个为什么线程不安全
* 我们假设有多个线程1,线程2都需要使用这个单例对象。而恰巧,线程1在判断完s==null后突然交换了cpu的使用权,变为线程2执行,
* 由于s仍然为null,那么线程2中就会创建这个Singleton的单例对象。之后线程1拿回cpu的使用权,而正好线程1之前暂停的位置就是判断s是否为null之后,
* 创建对象之前。这样线程1又会创建一个新的Singleton对象。
3 懒汉式:线程安全
public class LazySingleObjectSyn { private static LazySingleObjectSyn lazySingleObjectSyn; private LazySingleObjectSyn(){} public static synchronized LazySingleObjectSyn getLazySingleObjectSyn(){ if (lazySingleObjectSyn==null){ lazySingleObjectSyn=new LazySingleObjectSyn(); } return lazySingleObjectSyn; } }
4 双检锁/双重校验锁
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
5 静态内部内
public class StaticSingle { private StaticSingle() {} public static class Sin{ private final static Sin sin=new Sin(); } public static Sin getInstance(){ return Sin.sin; } }
6 枚举
public enum Singleton { INSTANCE; public void whateverMethod() { } }