单例模式
- 定义:程序运行时,在java虚拟机中只存在该类的一个实例对象。
- demo:
| package mode; |
| |
| public class SingleDemo { |
| |
| private static SingleDemo instance = new SingleDemo(); |
| |
| private SingleDemo() {} |
| |
| public static SingleDemo getInstance() { |
| return instance; |
| } |
| |
| public void showMessage() { |
| System.out.println("这里是重要的信息"); |
| } |
| } |
| class SingleAply{ |
| public static void main(String[] args) { |
| SingleDemo singleDemo = SingleDemo.getInstance(); |
| singleDemo.showMessage(); |
| } |
| } |
实现方式
懒汉式-线程不安全
|
懒汉式_线程不安全 |
优点 |
1.起到了延迟加载的效果 |
缺点 |
1.只能在单线程下使用 2.如果在多线程下,一个线程进入了if(single==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这是便会产生多个实例。所以多线程不可以使用 |
结论 |
在实际开发中,不要使用这种方式 |
| public class LazyNotSafe { |
| private static LazyNotSafe instance; |
| private LazyNotSafe() {} |
| |
| public LazyNotSafe getInstance() { |
| if (instance == null) { |
| instance = new LazyNotSafe(); |
| } |
| return instance; |
| } |
| } |
懒汉式-线程安全
|
懒汉式_线程安全 |
优点 |
1.解决了线程不安全问题 |
缺点 |
1.效率太低,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。 2.而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低。 |
结论 |
在实际开发中,不要使用这种方式 |
| public class LazySafe { |
| private static LazySafe instance; |
| private LazySafe() {} |
| |
| public static synchronized LazySafe getInstance() { |
| if (instance == null) { |
| instance = new LazySafe(); |
| } |
| return instance; |
| } |
| } |
懒汉式-线程不安全同步代码块
|
懒汉式_同步代码块 |
优点 |
延迟加载 |
缺点 |
1.本意是对线程安全的懒汉式进行改进,因为其同步方法效率太低,改为同步产生的实例化代码块 2.线程不能同步。假如一个线程进入了if(instance==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例 注意:synchronized同步代码块中,当释放锁后,会继续向下执行 |
结论 |
在实际开发中,不能用这种方式 |
| public class LazyNoSafePiece { |
| private static LazyNoSafePiece instance; |
| private LazyNoSafePiece() {} |
| |
| public LazyNoSafePiece getInstance() { |
| if (instance == null) { |
| synchronized(LazyNoSafePiece.class) { |
| instance = new LazyNoSafePiece(); |
| } |
| } |
| return instance; |
| } |
| } |
饿汉式-静态变量/静态代码块
|
饿汉式_静态变量/静态代码块 |
优点 |
在类加载的时候完成了实例化,避免了线程同步问题。 |
缺点 |
在类装载的时候就完成实例化,没有达到延迟加载的效果。如果从头到尾未使用过这个实例,则会造成内存的浪费 |
结论 |
这种单例模式可以使用,但可能会造成内存的浪费 |
| class HungrySafe { |
| private static HungrySafe instance = new HungrySafe(); |
| private HungrySafe() {} |
| public static HungrySafe getInstance() { |
| return instance; |
| } |
| } |
| class HungrySafe2 { |
| private static HungrySafe2 instance; |
| private HungrySafe2() {} |
| static { |
| instance = new HungrySafe2(); |
| } |
| public static HungrySafe2 getInstance() { |
| return instance; |
| } |
| } |
双重检查(推荐使用)
|
双重检查 |
优点 |
1.线程安全 2.延迟加载 3.效率较高 4.实例化代码只用执行一次,后面再次访问时,判断第一层if(xxx==null),直接return实例化对象,也避免的反复进行方法同步。 |
结论 |
在实际开发中,推荐使用 |
| public class DoubleCheck { |
| private DoubleCheck doubleCheck; |
| private DoubleCheck() {} |
| |
| public DoubleCheck getInstance() { |
| if (doubleCheck == null) { |
| synchronized(DoubleCheck.class) { |
| if (doubleCheck == null) { |
| doubleCheck = new DoubleCheck(); |
| } |
| } |
| } |
| return doubleCheck; |
| } |
| } |
静态内部类(推荐使用)
|
优势 |
如何保证实例时只有一个线程? 即如何保证线程安全? |
类的静态属性只会在第一次加载类的时候初始化,在类进行初始化时,别的线程是无法进入的,所以线程安全 |
如何实现延迟加载 |
利用静态内部类,不是在xxx类被装载时立即实例化,而是在调用getInstance方法时,才会装载xxx类,从而完成xxx类的实例化 |
| public class InnerClass { |
| |
| private static volatile InnerClass instance; |
| private InnerClass() {} |
| |
| private static class InnerInstance { |
| private final static InnerClass instance = new InnerClass(); |
| } |
| |
| public static InnerClass getInstance() { |
| return InnerInstance.instance; |
| } |
| } |
枚举
|
枚举 |
优点 |
1.能避免多线程同步问题 2.自动支持序列化机制,防止反序列化重新创建新的对象,防止多次实例化。 注意1:枚举类的内部定义的枚举值就是该类的实例(且必须在第一行定义,当类初始化时,这些枚举值会被实例化)。 线程安全由于JVM保证,因为ClassLoader进行类加载时,加了同步锁synchronized。 注意2:枚举类型在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象,而不是通过调用 readObject()方法来返回一个新创建出来的对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。 |
| enum EnumSingleton { |
| INSTANCE; |
| public void sayOK() { |
| System.out.println("ok"); |
| } |
| } |
| |
| class A { |
| public static void main(String[] args) { |
| System.out.println(EnumSingleton.INSTANCE); |
| EnumSingleton.INSTANCE.sayOK(); |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2022-08-15 11. azkaban将调度结果发送到邮箱
2022-08-15 12. scala配置与创建