单例模式

单例模式
单例模式的目的(作用):
  单例模式的目的是为了让外界只能得到一个”类的实例对象”.
单例模式的创作思路:
  由上述单例模式的作用,我们其实可以倒推出单例模式的写法.
  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虚拟机加载类的同时也被加载.
       即不管是否通过类名调用,对象本身已经存在了.
懒汉式:
       在创建类的时候不会创建实例对象,当外界通过类名调用的时候才创建对象(被动式创建).

本人只是初学者,文中可能存在错误,在您阅读的过程中若是发现问题,欢迎留言,谢谢!!!

  

点赞