设计模式之单例模式
1个回答
展开全部
本文开始整个设计模式的系列学习,希望通过不断的学习,可以对设计模式有整体的掌握,并在项目中根据实际的情况加以利用。
单例模式是指一个类仅允许创建其自身的一个实例,并提供对该实例的访问权限。它包含静态变量,可以容纳其自身的唯一和私有实例。它被应用于这种场景——用户希望类的实例被约束为一个对象。在需要单个对象来协调整个系统时,它会很有帮助。
1、单例类只能有一个实例
2、单例类必须自己创建自己的唯一实例
3、单例类必须给其他所有对象提供这一实例
1.尽量使用懒加载
2.双重检索实现线程安全
3.构造方法为private
4.定义静态的Singleton instance对象和getInstance()方法
单例模式至少有六种写法。
作为一种重要的设计模式,单例模式的好处有:
1、控制资源的使用,通过线程同步来控制资源的并发访问
2、控制实例的产生,以达到节约资源的目的
3、控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。但其实通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。
虽然也是只有一个线程能够执行,假如线程B先执行,线程B获得锁,线程B执行完之后,线程 A获得锁,但是此时没有检查singleton是否为空就直接执行了,所以还会出现两个singleton实例的情况。
既然懒汉式是非线程安全的,那就要改进它。最直接的想法是,给getInstance方法加锁不就好了,但是我们不需要给方法全部加锁啊,只需要给方法的一部分加锁就好了。基于这个考虑,引入了双检锁(Double Check Lock,简称DCL)的写法:
使用volatile 的原因:
对于JVM而言,它执行的是一个个Java指令。在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间, 然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就使出错成为了可能,我们仍然以A、B两个线程为例:
加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。
枚举类实现单例模式是 effective java 作者极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。因为枚举类没有构造方法,可以防止反序列化操作。
1、除枚举方式外, 其他方法都会通过反射的方式破坏单例,反射是通过调用构造方法生成新的对象,所以如果我们想要阻止单例破坏,可以在构造方法中进行判断,若已有实例, 则阻止生成新的实例,解决办法如下:
2、如果单例类实现了序列化接口Serializable, 就可以通过反序列化破坏单例,所以我们可以不实现序列化接口,如果非得实现序列化接口,可以重写反序列化方法readResolve(), 反序列化时直接返回相关单例对象。
Runtime是一个典型的例子,看下JDK API对于这个类的解释"每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过getRuntime方法获取当前运行时。应用程序不能创建自己的Runtime类实例。",这段话,有两点很重要:
1、每个应用程序都有一个Runtime类实例
2、应用程序不能创建自己的Runtime类实例
只有一个、不能自己创建,是不是典型的单例模式?看一下,Runtime类的写法:
为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现。
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
关于单例模式的漫画分析: https://mp.weixin.qq.com/s/f-sJIZHr7JUa31gKTllSFQ
单例模式的优缺点、注意事项、使用场景
单例模式是指一个类仅允许创建其自身的一个实例,并提供对该实例的访问权限。它包含静态变量,可以容纳其自身的唯一和私有实例。它被应用于这种场景——用户希望类的实例被约束为一个对象。在需要单个对象来协调整个系统时,它会很有帮助。
1、单例类只能有一个实例
2、单例类必须自己创建自己的唯一实例
3、单例类必须给其他所有对象提供这一实例
1.尽量使用懒加载
2.双重检索实现线程安全
3.构造方法为private
4.定义静态的Singleton instance对象和getInstance()方法
单例模式至少有六种写法。
作为一种重要的设计模式,单例模式的好处有:
1、控制资源的使用,通过线程同步来控制资源的并发访问
2、控制实例的产生,以达到节约资源的目的
3、控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。但其实通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。
虽然也是只有一个线程能够执行,假如线程B先执行,线程B获得锁,线程B执行完之后,线程 A获得锁,但是此时没有检查singleton是否为空就直接执行了,所以还会出现两个singleton实例的情况。
既然懒汉式是非线程安全的,那就要改进它。最直接的想法是,给getInstance方法加锁不就好了,但是我们不需要给方法全部加锁啊,只需要给方法的一部分加锁就好了。基于这个考虑,引入了双检锁(Double Check Lock,简称DCL)的写法:
使用volatile 的原因:
对于JVM而言,它执行的是一个个Java指令。在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间, 然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就使出错成为了可能,我们仍然以A、B两个线程为例:
加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。
枚举类实现单例模式是 effective java 作者极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。因为枚举类没有构造方法,可以防止反序列化操作。
1、除枚举方式外, 其他方法都会通过反射的方式破坏单例,反射是通过调用构造方法生成新的对象,所以如果我们想要阻止单例破坏,可以在构造方法中进行判断,若已有实例, 则阻止生成新的实例,解决办法如下:
2、如果单例类实现了序列化接口Serializable, 就可以通过反序列化破坏单例,所以我们可以不实现序列化接口,如果非得实现序列化接口,可以重写反序列化方法readResolve(), 反序列化时直接返回相关单例对象。
Runtime是一个典型的例子,看下JDK API对于这个类的解释"每个Java应用程序都有一个Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过getRuntime方法获取当前运行时。应用程序不能创建自己的Runtime类实例。",这段话,有两点很重要:
1、每个应用程序都有一个Runtime类实例
2、应用程序不能创建自己的Runtime类实例
只有一个、不能自己创建,是不是典型的单例模式?看一下,Runtime类的写法:
为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现。
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
关于单例模式的漫画分析: https://mp.weixin.qq.com/s/f-sJIZHr7JUa31gKTllSFQ
单例模式的优缺点、注意事项、使用场景
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询