【软件编程】Singleton单例模式
-----------设计模式之 单例模式---------------
单例模式是创建模式中普遍采用的一种。使用单例模式可以确保某个类只会有一个实例被创建。
它的特点:
变量=私有+静态
构造函数=私有
方法=公有+静态
Java 语言中单例模式的一个最重要的特点是类的构造器是私有的。从而避免外界利用构造器直接创建出任意多的实例。
通俗的说,就是外部类不能随便就new一个单例类的对象了,因为构造器私有,受权限限制。值得指出的是,由于构造器是私有的,因此,此类不能被继承。
两种形式:
饿汉式:
在类加载到内存时就初始化实例了。
推荐使用它的原因:
1.是线程安全的,
2.在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变 。
懒汉式:
在类第一次被引用时将自己实例化。话句话就是,第一次调用该单子类方法的时候被初始化。
1.如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。
2.synchronized的重要性:
如果在多线程的环境,程序可能会有两个甚至两个以上的singleton对象被创建出来,从而造成错误。为了克服没有线程安全的缺点,我们使用synchronized。同步化实际上只在singleton对象第一次被赋值之前才有用。在singleton对象有了值以后,同步化实际上变成了一个不必要的瓶颈。于是就有了双重检查成例。(见代码@改进版懒汉式),
因为java不支持双重检查成例,由于 Java 内存模型的一些细节的原因,会出问题。专家建议不要使用此版本。
详情:登录IBM-中国,网站地址:http://www.ibm.com/developerworks/cn/java/j-dcl.html
优点:
从速度和反应时间角度来讲,饿汉式好。
从资源利用效率上说,懒汉式好。
一些资深专家建议使用饿汉式,如果非要使用懒汉式,就用原始版的懒汉式。
补充:
一些资源管理器常常设计成单例模式。
当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费时间。 这意味着出现多线程同时首次引用此类的机率变得较大。
比方说,(如果想使用懒汉式的话)线程1首次引用此类,初始化还未结束,时间片就分给了线程2,可能由于优先级的原因。线程2占用时间挺长,把类初始化结束了,singleton对象有了值,这时,线程1开始工作了,那么此时它的singleton对象变量是null还是线程2的值呢。会造成系统异常。必须处理好在多个线程同时首次引用此类时的访问限制问题。
2
3 //单例模式
4 public class Singleton
5 {
6 public static void main(String[] args)
7 {
8 SingTest st=SingTest.getInstance();
9 System.out.println(st);
10 }
11 }
12
13
14 /**
15 * ----------------专家推荐饿汉式-------------------
16 */
17
18
19 class SingTest
20 {
21 private static SingTest instance = new SingTest();
22 private SingTest(){}
23 public static SingTest getInstance()
24 {
25 return instance;
26 }
27 }
28
29
30
31 /*--------------原始版懒汉式--------------------*/
32
33 /*class SingTest
34 {
35 private static SingTest instance = null;
36 private SingTest(){}
37 public static synchronized SingTest getInstance()
38 {
39 if(instance==null)
40 {
41 instance=new SingTest();
42 }
43 return instance;
44 }
45 }*/
46
47
48 /**
49 * --------------改进版懒汉式-----------------------
50 */
51
52 /*
53 * 此版虽然改进了同步化处理的小瓶颈问题。但是java不支持双重检测成例。
54 在执行下面代码时,由于一些不太常见的 Java 内存模型细节的原因,并不能保证这个双重检查锁定习语有效。
55 它偶尔会失败,而不是总失败。此外,它失败的原因并不明显,还包含 Java 内存模型的一些隐秘细节。
56 这些事实将导致代码失败,原因是双重检查锁定难于跟踪。
57 */
58 /*class SingTest
59 {
60 private static SingTest instance = null;
61 private SingTest(){}
62 public static SingTest getInstance()
63 {
64 if(instance==null)
65 {
66 synchronized(SingTest.class)
67 {
68 if(instance==null)
69 {
70 instance=new SingTest();
71 }
72 }
73 }
74 return instance;
75 }
76 }*/
77
78
79
80
signature:
-------------------------------------------------------------------
向着理想进军!因为我是Vincent【象征着征服与执着】