单例模式:确保一个类只有一个实例,并提供一个全局访问点。
要想保证一个类只有一个实例,我们不能将构造方法暴露出去,否则调用方就可能通过你提供的构造方法去实例化该类的实例,这样我们就无法保证该类只有一个实例了。因此,我们不能给类的构造方法赋予public的访问权限。
单例模式的实例化分为两种:急切实例化和延迟实例化
急切实例化:依赖JVM在加载这个类时马上创建此唯一的单件实例,通常表现为一个静态引用。如果程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,我们可以采取急切实例化的方式创建单件。
public class Product {
//静态成员——将在JVM加载该类的时候就完成对象的实例化
private static Product product = new Product();
private Product(){
}
public static Product newInstance(){
//始终返回被加载时创建的静态成员实例
return product;
}
}
急切实例化单例模式UML图:
延迟实例化:只在真正需要该类的实例的时候才实例化。通常在创建和运行时负担比较重的时候选用此种方案。
public class Product {
//静态成员——之前先不去实例化对象
private static Product product;
private Product(){
}
public static Product newInstance(){
//只有在需要该类的时候调用此方法时才去完成实例化
if(null == product){
product = new Product();
}
return product;
}
}
延迟实例化单例模式UML图:
延迟实例化所面临的线程安全问题:
很多人在使用延迟实例化单例模式时都没有考虑线程安全问题。我们看下面一段代码:
/**
* 延迟实例化单例模式
*/
public class Product {
private static Product product;
private Product(){
}
public static Product newInstance() throws Throwable{
if(null == product){
Thread.sleep(5000);//这时可能会有两个线程同时进入到这里
product = new Product();//之后可能会创建两个Product类的实例
}
return product;
}
}
上段代码有时也可能只会创建一个实例,这取决哪个线程抢占到执行权,但不排除创建两个实例的可能性,有兴趣的朋友可以自己多尝试几次,或者借助调试的手段手动切换两个线程的执行顺序,就会出现创建两个实例的情景。既然如此,我们以后就不要像上面的代码这样使用延时实例化。
如何解决
延迟实例化所面临的线程安全问题:
方法一:使用synchronized,如下所示:
/**
* 延迟实例化单例模式
*/
public class Product {
private static Product product;
private Product(){
}
public static synchronized Product newInstance() throws Throwable{
if(null == product){
product = new Product();
}
return product;
}
}
上面的代码虽然能解决线程安全问题,但是每次调用newInstance方法时都会被同步,无疑会带来性能损耗,你必须知道同步一个方法可能造成程序执行效率下降100倍。如果你可以接受这样的额外损耗,你大可可以这样来用(即简单又有效),如果你可能需要频繁的调用这个同步方法,又无法接受这样的性能损失,可能就得想其他的办法啦。
方法二:使用“双重检查加锁”,如下所示:
/**
* 延迟实例化单例模式
*/
public class Product {
private volatile static Product product;//使用volatile
private Product(){
}
public static Product newInstance() throws Throwable{
if(null == product){
synchronized(Product.class){//保护起来
if(null == product){//之后再次检查
product = new Product();
}
}
}
return product;
}
}
这样做比直接使用同步方法带来的损耗要低很多。如果你不想使用synchronized,也可以使用阻塞队列,JDK也是这么推荐的。
方法三:使用急切实例化,当然之前介绍了急切实例化也有他的缺点,如果你能接受的话,这也是个简单有效的方案。
单例模式请注意多个ClassLoder
每个类加载器都定义了一个名空间,如果有两个以上的类加载器,不同的类加载器可能会加载同一个类,从整个程序来看,同一个类被加载多次,如果这样的事情发生在单件上,就会产生多个实例并存的“单件”,所以需要引起注意。
参考资料:
Head First 设计模式 (中国电力出版社)
- 大小: 3.5 KB
- 大小: 3.2 KB
分享到:
相关推荐
设计模式C++学习之单例模式(Singleton)
设计模式总结-模板设计模式,单例模式(singleTon)
设计模式里面的单例模式程序 package com.rrppff; public class Singleton { private static String name; public static String getName() { return name; } public static void setName(String name) { ...
php /** * 单例模式 * * 保证一个类仅有一个实例,并提供一个访问它的全局访问点 * */ class Singleton { static private $_instance = null; private function __construct() { } static public function ...
单例模式(Singleton Pattern 单件模式或单元素模式),是常见的一种设计模式,它有三个特点 1.只能有一个实例 2.必须自行创建这个实例 3.必须给其他对象提供这一实例 下面用PHP代码实现一下 <?PHP /** *...
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 学习demo
本文实例讲述了JS 设计模式之:单例模式定义与实现方法。分享给大家供大家参考,具体如下: 良好的设计模式可以显著提高代码的可读性,降低复杂度和维护成本。笔者打算通过几篇文章通俗地讲一讲常见的或者实用的设计...
C# 23种设计模式之单例模式源码
单例设计模式Singleton1
NULL 博文链接:https://wy649898543.iteye.com/blog/1431908
NULL 博文链接:https://linxingliang.iteye.com/blog/1217811
设计模式系列之01-单例模式(Singleton模式),很好的资源,理论实践结合讲述,逐步更新
简单的单例模式举例Singleton 分为恶汉式 懒汉式
java设计模式,单例模式的不同实现方式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个...
本文档,是利用C++来实现设计模式中的,单例模式,里面有内容说明和相关实例代码介绍
3. 单例模式(Singleton) 4 4.建造者模式(Builder) 4 5. 原型模式(Protype) 5 6.适配器模式(Adapter) 6 7.装饰模式(Decorator) 6 8.代理模式(Proxy) 7 9.外观模式(Facade) 7 10.桥接模式(Bridge) 7 ...
本文实例讲述了JS基于设计模式中的单例模式(Singleton)实现封装对数据增删改查功能。分享给大家供大家参考,具体如下: 单例模式 单例模式的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中...
IOS 单例设计模式实例Demo 单例 设计 模式 IOS Singleton
Java面向对象(高级)-- 单例(Singleton)设计模式