声明:设计模式相关文章收集整理于互联网,并且参考《Head First设计模式》,并非本人原创内容,本人旨在学习交流,并非有意冒犯,本人尽可能的注明来源出处。
所谓单件模式(单例模式),是指是某个类最多只能有一个实例对象。我们在编程中,实际上会经遇到这种情况,比如线程池、缓存、注册表对象、驱动对象等,上述这些情况,实际只能有一个实例,否则就会产生很多问题,如程序的行为异常、资源使用过量等。
典型的单件模式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Singleto{ private static Singleton uniqueinstance;//利用一个静态变量来保存实例 private Singleton(){//将构造函数声明为私有的 } public static Singleton getInstance(){ //用getInstance()实例化对象并返回对象 if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } //其他代码 |
我们可以从上述代码中看出,构造方法被声明为私有,外部首先就不能直接创建该类的实例。只有当调用getInstance()方法时,如果uniqueInstance为空才会去创建,这就是所谓的“延迟创建”,只在使用的时候创建。而之后在调用getInstance()方法时,如果uniqueInstance不为空,则返回它自己,这就保证了这个类的实例只有一个。
单件模式高级技巧:
在多线程中使用单件模式时,可能会遇到一些新的问题:假如有两个线程同时调用getInstance()方法,则会出现如下的现象。
1 2 3 4 5 6 7 8 9 10 11 12 |
public static Singleton getInstance(){//线程1 public static Singleton getInstance(){ //线程2 if(uniqueInstance == null){ if(uniqueInstance == null){ uniqueInstance = new Singleton();//创建对象1 } return uniqueInstance; } uniqueInstance = new Singleton(); //创建对象2 } return uniqueInstance; |
假如入上述两个线程中的代码按上述顺序跑下来,我们就得到了两个实例对象。那么怎样去避免这种情况发生呢?如下提供了三种方案:
1.同步getInstance()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Singleto{ private static Singleton uniqueinstance; //利用一个静态变量来保存实例 private Singleton(){//将构造函数声明为私有的 } public static synchronized Singleton getInstance(){ //用getInstance()实例化对象并返回对象 if(uniqueInstance == null){ uniqueInstance = new Singleton(); } return uniqueInstance; } //其他代码 |
优点:既简单又有效
缺点:每次调用getInstance()都会执行同步,影响程序执行效率,getInstance()不适合用在频繁运行的地方。
2.立即创建实例,不延迟实例化:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Singleto{ private static Singleton uniqueinstance = new Singleton(); //利用一个静态变量来保存实例 private Singleton(){//将构造函数声明为私有的 } public static Singleton getInstance(){ //用getInstance()实例化对象并返回对象 return uniqueInstance; } //其他代码 |
优点:同样简单有效
缺点:使用这种方法,需要使用者不在意这个类的对象所占用的资源。并且它依赖于JVM。在加载这个类的时候马上创建一个唯一的单件实例,同时保证任何线程在访问uniqueInstance静态变量前,一定先创建该实例。
3.双重检查加锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class Singleto{ private volatile static Singleton uniqueinstance; //利用一个静态变量来保存实例 private Singleton(){//将构造函数声明为私有的 } public static Singleton getInstance(){ //用getInstance()实例化对象并返回对象 if(uniqueInstance == null){ synchronized(Singleton.this){ if(uniqueInstance == null){ //进入同步区后,再检查一次 uniqueInstance = new Singleton(); } } } return uniqueInstance; } //其他代码 |
优点:利用双重检查加锁,只有第一次才会执行同步
缺点:在1.4及更早版本的java中,volatile关键字的实现可能会导致双重检查加锁失效。
参考:
《Head First 设计模式》
0 条评论