【JAVA】:单例设计模型

2020/5/25 Java

# 单例设计模型

一、什么是单例设计模型        这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

二、实际生活举例 (1)一个学校只有一个正校长。 (2)在一台电脑上有俩台打印机,但俩台打印机不能同时打印同一份文件。

三、优缺点 (1)在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。 (2)没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

四、实现方法

(1)懒汉式

public class Demo1 {
  private static Demo1 demo=null;
  private Demo1(){//构造方法私有化

  }
  public void sayHello(){
	  System.out.println("懒汉式(线程不安全):CSDN");
  }
  public static Demo1 getdemo(){
	  if(demo==null){
		 return new Demo1();
	  }
		  return demo;
	}
  public static void main(String[] args) {
	Demo1 demo=Demo1.getdemo();
	demo.sayHello();
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

评价:        该设计模型由于没有加锁(synchronized),故线程不安全

(2)懒汉式

public class Demo2 {
	private static Demo2 demo=null;
	  private Demo2(){//构造方法私有化

	  }
	  public void sayHello(){
		  System.out.println("懒汉式(线程安全):CSDN");
	  }
	  public static synchronized Demo2 getdemo(){
		  if(demo==null){
			 return new Demo2();
		  }
			  return demo;
		}
	  public static void main(String[] args) {
		Demo2 demo=Demo2.getdemo();
		demo.sayHello();
	   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

评价:        该设计模型由于有加锁(synchronized),故线程安全。只有第一次获取该类实例化对象时需要创建对象,避免了内存的浪费,也支持多线程。但有个缺点是,加锁会影响效率

(3)饿汉式

public class Demo3 {
   private static Demo3 demo=new Demo3();
   public static Demo3 getDemo3(){
	   return demo;
   }
   public void sayHello(){
	   System.out.println("饿汉式(线程安全):Hello CSDN");
   }
   public static void main(String[] args) {
	Demo3 demo=Demo3.getDemo3();
    demo.sayHello();
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

评价:        但该类被加载完成后,该类的实例化对象就已经被创建了,这可能会导致了内存浪费。但该设计形式没有加锁(synchronized),故效率高,并且支持多线程

(4)双检锁/双重校验锁

public class Demo4 {
    private volatile static Demo4 demo;
    private Demo4(){}
    public void sayhello(){
    	System.out.println("双检锁/双重校验锁:Hello,CSDN");
    }
    public static Demo4 getdemo(){
    	if(demo==null){
    		synchronized (Demo4.class) {
				if(demo==null){
					demo=new Demo4();
				}
			}
    	}
    	return demo;
    }
    public static void main(String[] args) {
		Demo4 demo=Demo4.getdemo();
		demo.sayhello();
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

评价:        安全且在多线程上能够保持较高性能。

(5)登记式/静态内部类

public class Demo5 {
	//内部静态类
    private static class Demo6{
    	private static final Demo5 demo=new Demo5();
    }
    private Demo5(){}

    public void sayHello(){
    	System.out.println("登记式/静态内部类:Hello,CSDN");
    }
    public static final Demo5 getdemo(){
    	return Demo6.demo;
    }
    public static void main(String[] args) {
		Demo5 demo=Demo5.getdemo();
	    demo.sayHello();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

评价:        该设计模型达到的目的以及性能上跟双重校验锁一样的。该模型是也是利用了Java 加载机制,来保证初始化 demo 时只有一个线程,与饿汉式不同。饿汉式是主要该类被装载就已经实例化了,而静态内部类是该类被装载后,该类的实例化对象并没有被创建,而是需要调用静态方法 getdemo()来获取对象。        这俩种设计形式相比,最后一种的设计模式是比较好的,当该类被加载后,并没有被实例化,当需要该对象是只要调用该类的静态内部类来实例化对象即可,减少内存资源的浪费

(6)枚举法        枚举法与前面的五种相比较下,是有很大的优点的,设计更加严谨,实现也比较简单。为了介绍的更加详细在这里我不作介绍,但我会在下一篇博客进行详细介绍。