单例模式
单例模式的目的(作用):
单例模式的目的是为了让外界只能得到一个”类的实例对象”.
单例模式的创作思路:
由上述单例模式的作用,我们其实可以倒推出单例模式的写法.
1.一般来说,在创建一个类的同时也会提供公开(public)的无参和有参构造方法,这样在外界就能创建类的实例对象,并且每new一次都会创建一个新的实例对象.这就和单例模式是矛盾的,单 例模式的实例对象有且只有一个.那么也就是说,在创建类的同时将其构造方法私有化(private).这样外界就无法通过new来创建类的实例对象,这样就不会产生多个不同的实例对象.
结论: 构造方法私有化.
2.既然已经将构造方法私有化了,外界已经无法通过new来创建实例对象了,那么我们就必须在创建类的同时在本类中创建一个本类的实例对象.构造方法私有化之后在外界其他类中能 new创建实例对象,但是可以在本类中可以通过new来创建实例对象(这与private关键字的特点有关).
既然在外界不能new实例对象,那么在外界获得实例对象的方式只有可能是通过类名的方式调用.
那么问题来了? 通过类名来调用什么呢?
2.1.可以调用公开的静态的成员变量.
例:public static String s = new String();
这样虽然可以用类名来调用,但是每调用一次,相应的在表达式右边就是new一次,
还是会创建多个String的实例对象.这与我们的本意不相符.
这时就需要final关键字来修饰成员变量,表示最终的不可变的.
总结:public static final String s = new String();
2.2.可以调用公开的静态的成员方法.
例:public static String getInstance(){}
这个方法我们可以得到String的实例对象,在这种情况下,就需要将公开的静态的
成员变量私有化.即:private static String s = new String();
总结:
2.2.1.类的成员变量私有化
private static String s = new String();
2.2.2提供公开的静态的获得实例对象的方法
public static String getInstance(){ return s;}
3.根据上述的思路创建单例模式
单例模式1_1(饿汉式):
package com.Singleton.deom1; public class Singleton { public static void main(String[] args) { //测试 Singleton is1 = Singleton.getInstance(); Singleton is2 = Singleton.getInstance(); System.out.println(is1 == is2); } //1.构造方法私有化 private Singleton() {} //2.私有的Singleton的对象 private static Singleton s = new Singleton(); //3.提供公开的静态的获得Singleton实例对象的方法 public static Singleton getInstance() { return s; } }
程序运行结果
1 true
单例模式1_2(饿汉式):
属于1_1的变化形式(根据2.1.可以调用公开的静态的成员变量)
1 package com.Singleton.deom1_2; 2 3 public class Singleton { 4 public static void main(String[] args) throws Exception { 5 //测试 6 Singleton s1 = Singleton.s; 7 Singleton s2 = Singleton.s; 8 System.out.println(s1 == s2); 9 } 10 11 //1.构造方法私有化 12 private Singleton() {} 13 14 //2.私有的Singleton的对象 15 public static final Singleton s = new Singleton(); 16 }
程序运行结果
1 true
单例模式2(懒汉式):
1 package com.Singleton.deom2; 2 3 public class Singleton { 4 public static void main(String[] args) { 5 //测试 6 Singleton is1 = Singleton.getInstance(); 7 Singleton is2 = Singleton.getInstance(); 8 System.out.println(is1 == is2); 9 } 10 11 //1.构造方法私有化 12 private Singleton() {} 13 14 //2.私有的Singleton的对象 15 private static Singleton s; 16 17 //3.提供公开的静态的获得Singleton实例对象的方法 18 public static Singleton getInstance() { 19 //4.判断,当s == null时,则创建对象 20 if(s == null) { 21 s = new Singleton(); 22 } 23 return s; 24 } 25 }
程序运行结果
1 true
对于上述懒汉式在单线程情况下没有问题,但是在多线程情况下就会出现问题,即创建多个对象.程序如下:在多线程(以100个线程为例)情况下,创建单例模式.
1 package com.Singleton.deom2_2; 2 3 public class Singleton { 4 public static void main(String[] args) { 5 //测试 6 for (int i = 0; i < 100; i++) { 7 new Thread() { 8 public void run() { 9 System.out.println(Singleton.getInstance()); 10 } 11 }.start(); 12 } 13 } 14 15 //1.构造方法私有化 16 private Singleton() {} 17 18 //2.私有的Singleton的对象 19 private static Singleton s; 20 21 //3.提供公开的静态的获得Singleton实例对象的方法 22 public static Singleton getInstance() { 23 //4.判断,当s == null时,则创建对象 24 if(s == null) { 25 s = new Singleton(); 26 } 27 return s; 28 } 29 }
程序运行结果
1 ***com.Singleton.deom1.Singleton@3d33e0a5*** 2 com.Singleton.deom1.Singleton@169c78e8 3 com.Singleton.deom1.Singleton@169c78e8 4 com.Singleton.deom1.Singleton@169c78e8 5 com.Singleton.deom1.Singleton@169c78e8 6 com.Singleton.deom1.Singleton@169c78e8 7 com.Singleton.deom1.Singleton@169c78e8 8 com.Singleton.deom1.Singleton@169c78e8 9 com.Singleton.deom1.Singleton@169c78e8 10 com.Singleton.deom1.Singleton@169c78e8 11 com.Singleton.deom1.Singleton@169c78e8 12 com.Singleton.deom1.Singleton@169c78e8 13 com.Singleton.deom1.Singleton@169c78e8 14 com.Singleton.deom1.Singleton@169c78e8 15 com.Singleton.deom1.Singleton@169c78e8 16 com.Singleton.deom1.Singleton@169c78e8 17 com.Singleton.deom1.Singleton@169c78e8 18 com.Singleton.deom1.Singleton@169c78e8 19 com.Singleton.deom1.Singleton@169c78e8 20 com.Singleton.deom1.Singleton@169c78e8 21 com.Singleton.deom1.Singleton@169c78e8 22 com.Singleton.deom1.Singleton@169c78e8 23 com.Singleton.deom1.Singleton@169c78e8 24 com.Singleton.deom1.Singleton@169c78e8 25 com.Singleton.deom1.Singleton@169c78e8 26 com.Singleton.deom1.Singleton@169c78e8 27 com.Singleton.deom1.Singleton@169c78e8 28 com.Singleton.deom1.Singleton@169c78e8 29 com.Singleton.deom1.Singleton@169c78e8 30 com.Singleton.deom1.Singleton@169c78e8 31 com.Singleton.deom1.Singleton@169c78e8 32 com.Singleton.deom1.Singleton@169c78e8 33 com.Singleton.deom1.Singleton@169c78e8 34 com.Singleton.deom1.Singleton@169c78e8 35 com.Singleton.deom1.Singleton@169c78e8 36 com.Singleton.deom1.Singleton@169c78e8 37 com.Singleton.deom1.Singleton@169c78e8 38 com.Singleton.deom1.Singleton@169c78e8 39 com.Singleton.deom1.Singleton@169c78e8 40 com.Singleton.deom1.Singleton@169c78e8 41 com.Singleton.deom1.Singleton@169c78e8 42 com.Singleton.deom1.Singleton@169c78e8 43 com.Singleton.deom1.Singleton@169c78e8 44 com.Singleton.deom1.Singleton@169c78e8 45 com.Singleton.deom1.Singleton@169c78e8 46 com.Singleton.deom1.Singleton@169c78e8 47 com.Singleton.deom1.Singleton@169c78e8 48 com.Singleton.deom1.Singleton@169c78e8 49 com.Singleton.deom1.Singleton@169c78e8 50 com.Singleton.deom1.Singleton@169c78e8 51 com.Singleton.deom1.Singleton@169c78e8 52 com.Singleton.deom1.Singleton@169c78e8 53 com.Singleton.deom1.Singleton@169c78e8 54 com.Singleton.deom1.Singleton@169c78e8 55 com.Singleton.deom1.Singleton@169c78e8 56 com.Singleton.deom1.Singleton@169c78e8 57 com.Singleton.deom1.Singleton@169c78e8 58 com.Singleton.deom1.Singleton@169c78e8 59 com.Singleton.deom1.Singleton@169c78e8 60 com.Singleton.deom1.Singleton@169c78e8 61 com.Singleton.deom1.Singleton@169c78e8 62 com.Singleton.deom1.Singleton@169c78e8 63 com.Singleton.deom1.Singleton@169c78e8 64 com.Singleton.deom1.Singleton@169c78e8 65 com.Singleton.deom1.Singleton@169c78e8 66 com.Singleton.deom1.Singleton@169c78e8 67 com.Singleton.deom1.Singleton@169c78e8 68 com.Singleton.deom1.Singleton@169c78e8 69 com.Singleton.deom1.Singleton@169c78e8 70 com.Singleton.deom1.Singleton@169c78e8 71 com.Singleton.deom1.Singleton@169c78e8 72 com.Singleton.deom1.Singleton@169c78e8 73 com.Singleton.deom1.Singleton@169c78e8 74 com.Singleton.deom1.Singleton@169c78e8 75 com.Singleton.deom1.Singleton@169c78e8 76 com.Singleton.deom1.Singleton@169c78e8 77 com.Singleton.deom1.Singleton@169c78e8 78 com.Singleton.deom1.Singleton@169c78e8 79 com.Singleton.deom1.Singleton@169c78e8 80 com.Singleton.deom1.Singleton@169c78e8 81 com.Singleton.deom1.Singleton@169c78e8 82 com.Singleton.deom1.Singleton@169c78e8 83 com.Singleton.deom1.Singleton@169c78e8 84 com.Singleton.deom1.Singleton@169c78e8 85 com.Singleton.deom1.Singleton@169c78e8 86 com.Singleton.deom1.Singleton@169c78e8 87 com.Singleton.deom1.Singleton@169c78e8 88 com.Singleton.deom1.Singleton@169c78e8 89 com.Singleton.deom1.Singleton@169c78e8 90 com.Singleton.deom1.Singleton@169c78e8 91 com.Singleton.deom1.Singleton@169c78e8 92 com.Singleton.deom1.Singleton@169c78e8 93 com.Singleton.deom1.Singleton@169c78e8 94 com.Singleton.deom1.Singleton@169c78e8 95 com.Singleton.deom1.Singleton@169c78e8 96 com.Singleton.deom1.Singleton@169c78e8 97 com.Singleton.deom1.Singleton@169c78e8 98 com.Singleton.deom1.Singleton@169c78e8 99 com.Singleton.deom1.Singleton@169c78e8 100 com.Singleton.deom1.Singleton@169c78e8
严格来说,上述算不上多线程,因为在循环的时候已经产生了时间差,不过即使是这样都已经导致了两个不同的Singleton对象产生,会对数据安全产生隐患.
优化上述懒汉式代码:
1 package com.Singleton.deom2_3; 2 3 public class Singleton { 4 public static void main(String[] args) throws Exception { 5 //测试 6 7 for (int i = 1; i <= 100; i++) { 8 new Thread() { 9 public void run() { 10 System.out.println(Singleton.getInstance()); 11 } 12 }.start(); 13 } 14 15 } 16 17 //1.构造方法私有化 18 private Singleton() {} 19 20 //2.私有的Singleton的对象 21 private static Singleton s; 22 23 //3.提供公开的静态的获得Singleton实例对象的方法 24 public static Singleton getInstance() { 25 //6.当在多线程环境下,这段程序被执行多次后必然会产生Singleton对象,因此在最外层加判断是 26 //为了不再进行synchronized (Singleton.class)操作,因为运行过程比较复杂,效率很低 27 if(s == null) { 28 //5.同步都需要的数据 29 synchronized (Singleton.class) { 30 //4.判断,当s == null时,则创建对象 31 if(s == null) { 32 s = new Singleton(); 33 } 34 } 35 } 36 return s; 37 } 38 }
程序运行结果
1 com.Singleton.deom1.Singleton@169c78e8 2 com.Singleton.deom1.Singleton@169c78e8 3 com.Singleton.deom1.Singleton@169c78e8 4 com.Singleton.deom1.Singleton@169c78e8 5 com.Singleton.deom1.Singleton@169c78e8 6 com.Singleton.deom1.Singleton@169c78e8 7 com.Singleton.deom1.Singleton@169c78e8 8 com.Singleton.deom1.Singleton@169c78e8 9 com.Singleton.deom1.Singleton@169c78e8 10 com.Singleton.deom1.Singleton@169c78e8 11 com.Singleton.deom1.Singleton@169c78e8 12 com.Singleton.deom1.Singleton@169c78e8 13 com.Singleton.deom1.Singleton@169c78e8 14 com.Singleton.deom1.Singleton@169c78e8 15 com.Singleton.deom1.Singleton@169c78e8 16 com.Singleton.deom1.Singleton@169c78e8 17 com.Singleton.deom1.Singleton@169c78e8 18 com.Singleton.deom1.Singleton@169c78e8 19 com.Singleton.deom1.Singleton@169c78e8 20 com.Singleton.deom1.Singleton@169c78e8 21 com.Singleton.deom1.Singleton@169c78e8 22 com.Singleton.deom1.Singleton@169c78e8 23 com.Singleton.deom1.Singleton@169c78e8 24 com.Singleton.deom1.Singleton@169c78e8 25 com.Singleton.deom1.Singleton@169c78e8 26 com.Singleton.deom1.Singleton@169c78e8 27 com.Singleton.deom1.Singleton@169c78e8 28 com.Singleton.deom1.Singleton@169c78e8 29 com.Singleton.deom1.Singleton@169c78e8 30 com.Singleton.deom1.Singleton@169c78e8 31 com.Singleton.deom1.Singleton@169c78e8 32 com.Singleton.deom1.Singleton@169c78e8 33 com.Singleton.deom1.Singleton@169c78e8 34 com.Singleton.deom1.Singleton@169c78e8 35 com.Singleton.deom1.Singleton@169c78e8 36 com.Singleton.deom1.Singleton@169c78e8 37 com.Singleton.deom1.Singleton@169c78e8 38 com.Singleton.deom1.Singleton@169c78e8 39 com.Singleton.deom1.Singleton@169c78e8 40 com.Singleton.deom1.Singleton@169c78e8 41 com.Singleton.deom1.Singleton@169c78e8 42 com.Singleton.deom1.Singleton@169c78e8 43 com.Singleton.deom1.Singleton@169c78e8 44 com.Singleton.deom1.Singleton@169c78e8 45 com.Singleton.deom1.Singleton@169c78e8 46 com.Singleton.deom1.Singleton@169c78e8 47 com.Singleton.deom1.Singleton@169c78e8 48 com.Singleton.deom1.Singleton@169c78e8 49 com.Singleton.deom1.Singleton@169c78e8 50 com.Singleton.deom1.Singleton@169c78e8 51 com.Singleton.deom1.Singleton@169c78e8 52 com.Singleton.deom1.Singleton@169c78e8 53 com.Singleton.deom1.Singleton@169c78e8 54 com.Singleton.deom1.Singleton@169c78e8 55 com.Singleton.deom1.Singleton@169c78e8 56 com.Singleton.deom1.Singleton@169c78e8 57 com.Singleton.deom1.Singleton@169c78e8 58 com.Singleton.deom1.Singleton@169c78e8 59 com.Singleton.deom1.Singleton@169c78e8 60 com.Singleton.deom1.Singleton@169c78e8 61 com.Singleton.deom1.Singleton@169c78e8 62 com.Singleton.deom1.Singleton@169c78e8 63 com.Singleton.deom1.Singleton@169c78e8 64 com.Singleton.deom1.Singleton@169c78e8 65 com.Singleton.deom1.Singleton@169c78e8 66 com.Singleton.deom1.Singleton@169c78e8 67 com.Singleton.deom1.Singleton@169c78e8 68 com.Singleton.deom1.Singleton@169c78e8 69 com.Singleton.deom1.Singleton@169c78e8 70 com.Singleton.deom1.Singleton@169c78e8 71 com.Singleton.deom1.Singleton@169c78e8 72 com.Singleton.deom1.Singleton@169c78e8 73 com.Singleton.deom1.Singleton@169c78e8 74 com.Singleton.deom1.Singleton@169c78e8 75 com.Singleton.deom1.Singleton@169c78e8 76 com.Singleton.deom1.Singleton@169c78e8 77 com.Singleton.deom1.Singleton@169c78e8 78 com.Singleton.deom1.Singleton@169c78e8 79 com.Singleton.deom1.Singleton@169c78e8 80 com.Singleton.deom1.Singleton@169c78e8 81 com.Singleton.deom1.Singleton@169c78e8 82 com.Singleton.deom1.Singleton@169c78e8 83 com.Singleton.deom1.Singleton@169c78e8 84 com.Singleton.deom1.Singleton@169c78e8 85 com.Singleton.deom1.Singleton@169c78e8 86 com.Singleton.deom1.Singleton@169c78e8 87 com.Singleton.deom1.Singleton@169c78e8 88 com.Singleton.deom1.Singleton@169c78e8 89 com.Singleton.deom1.Singleton@169c78e8 90 com.Singleton.deom1.Singleton@169c78e8 91 com.Singleton.deom1.Singleton@169c78e8 92 com.Singleton.deom1.Singleton@169c78e8 93 com.Singleton.deom1.Singleton@169c78e8 94 com.Singleton.deom1.Singleton@169c78e8 95 com.Singleton.deom1.Singleton@169c78e8 96 com.Singleton.deom1.Singleton@169c78e8 97 com.Singleton.deom1.Singleton@169c78e8 98 com.Singleton.deom1.Singleton@169c78e8 99 com.Singleton.deom1.Singleton@169c78e8 100 com.Singleton.deom1.Singleton@169c78e8
4.如何区分”饿汉式”和”懒汉式”?(个人的理解,仅供参考)
观察上述代码,会发现二者的区别主要体现在创建实例对象的时间上.
饿汉式:
在创建类的时候对象已经创建(主动式创建),并随着jvm虚拟机加载类的同时也被加载.
即不管是否通过类名调用,对象本身已经存在了.
懒汉式:
在创建类的时候不会创建实例对象,当外界通过类名调用的时候才创建对象(被动式创建).
本人只是初学者,文中可能存在错误,在您阅读的过程中若是发现问题,欢迎留言,谢谢!!!