大话--单例模式

定义

保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。

优点

1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。

2、避免对资源的多重占用(比如写文件操作)。

缺点

没有接口,扩展困难。

使用场景

需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多,但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)。

tips

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

关键代码

构造器一定是私有的

类图

 

 

使用单例模式的源码

java.lang.Runtime就使用了饿汉式的单例模式,因为Runtime一定会被使用,所以不会造成资源浪费。

 

 

具体实现

1.饿汉式(静态常量)

 1 package Singleton.Singletontest1;
 2 
 3 /**
 4  * @title: Singleton1
 5  * @Author yzhengy
 6  * @Date: 2020/7/30 20:22
 7  * @Question: 饿汉式(静态常量)
 8  */
 9 
10 /*
11  * @Date: 2020/7/30 20:23
12  * 1.构造器私有化(防止new对象)
13  * 2.类的内部创建对象
14  * 3.向外暴露一个静态的公共方法(getInstance)
15  * 优点:类装载时就完成了实例化,避免了多线程同步问题。
16  * 缺点:没有达到懒加载效果,如果一直不使用这个实例,会造成内存的浪费。
17  */
18 public class Singleton1 {
19     public static void main(String[] args) {
20         Singleton instance = Singleton.getInstance();
21         Singleton instance2 = Singleton.getInstance();
22         System.out.println(instance == instance2);//true
23         System.out.println(instance.hashCode()==instance2.hashCode());//true
24     }
25 }
26 
27 
28 class Singleton{
29     private Singleton(){}
30 
31     private final static Singleton instance = new Singleton();
32 
33     public static Singleton getInstance(){
34         return instance;
35     }
36 }
View Code

2.饿汉式(静态代码块)

 1 package Singleton.Singletontest2;
 2 
 3 /**
 4  * @title: Singleton2
 5  * @Author yzhengy
 6  * @Date: 2020/7/30 20:34
 7  * @Question: 饿汉式(静态代码块)
 8  */
 9 
10 /*
11  * @Date: 2020/7/30 20:23
12  * 1.构造器私有化(防止new对象)
13  * 2.类的内部创建对象实例
14  * 3.在静态代码块中创建单例对象
15  * 4.向外暴露一个静态的公共方法(getInstance)
16  * 优缺点:与饿汉式(静态常量)的优缺点相同
17  */
18 public class Singleton2 {
19     public static void main(String[] args) {
20         Singleton instance = Singleton.getInstance();
21         Singleton instance2 = Singleton.getInstance();
22         System.out.println(instance == instance2);//true
23         System.out.println(instance.hashCode()==instance2.hashCode());//true
24     }
25 }
26 
27 
28 class Singleton{
29     private Singleton(){}
30 
31     private static Singleton instance;
32 
33     static{
34         instance = new Singleton();
35     }
36 
37     public static Singleton getInstance(){
38         return instance;
39     }
40 }
View Code

3.懒汉式(线程不安全)

 1 package Singleton.Singletontest3;
 2 
 3 /**
 4  * @title: Singleton3
 5  * @Author yzhengy
 6  * @Date: 2020/7/31 8:35
 7  * @Question: 懒汉式(线程不安全)
 8  */
 9 
10 /*
11  * @Date: 2020/7/31 8:41
12  * 起到了懒加载的效果,但是只能在单线程时使用。
13  * 如果在多线程时使用,一个线程进入了if(instance==null)判断语句块,还未来得及往下执行,
14  * 另一个线程也通过了这个判断语句,这时就会产生多个实例。就会破坏单例模式。
15  */
16 public class Singleton3 {
17 
18     public static void main(String[] args) {
19         System.out.println("我是线程不安全的懒汉式!!!");
20         Singleton instance = Singleton.getInstance();
21         Singleton instance2 = Singleton.getInstance();
22         System.out.println(instance == instance2);//true
23         System.out.println(instance.hashCode()==instance2.hashCode());//true
24     }
25 
26 }
27 
28 class Singleton{
29     private Singleton(){}
30 
31     private static Singleton instance;
32 
33     //提供一个静态公有方法,当时用到该方法时,才会创建instance。(懒汉式的核心)
34     public static Singleton getInstance(){
35         if (instance == null)
36             instance = new Singleton();
37         return instance;
38     }
39 }
View Code

4.懒汉式(线程安全,同步方法)

 1 package Singleton.Singletontest4;
 2 
 3 /**
 4  * @title: Singleton4
 5  * @Author yzhengy
 6  * @Date: 2020/7/31 8:47
 7  * @Question: 懒汉式(线程安全,同步方法)
 8  */
 9 
10 /*
11  * @Date: 2020/7/31 8:47
12  * 在线程不安全的懒汉式的基础上,直接加一个Synchronized锁,保证线程安全。
13  * 缺点:每个线程想获取类的实例时,执行getInstance()方法都要进行同步,方法同步效率太低。
14  *      其实这个方法执行一次实例化代码就可以了,后面想获取该类实例直接return就可以了。
15  */
16 public class Singleton4 {
17 
18     public static void main(String[] args) {
19         System.out.println("我是线程安全的懒汉式!!!");
20         Singleton instance = Singleton.getInstance();
21         Singleton instance2 = Singleton.getInstance();
22         System.out.println(instance == instance2);//true
23         System.out.println(instance.hashCode()==instance2.hashCode());//true
24     }
25 
26 }
27 
28 class Singleton{
29     private Singleton(){}
30 
31     private static Singleton instance;
32 
33     //提供一个静态公有方法,当时用到该方法时,才会创建instance。(懒汉式的核心)
34     public static synchronized Singleton getInstance(){
35         if (instance == null)
36             instance = new Singleton();
37         return instance;
38     }
39 }
View Code

5.懒汉式(线程不安全,同步代码块)

 1 package Singleton.Singletontest5;
 2 
 3 /**
 4  * @title: Singleton5
 5  * @Author yzhengy
 6  * @Date: 2020/7/31 8:52
 7  * @Question: 懒汉式(线程不安全,同步代码块)
 8  */
 9 
10 /*
11  * @Date: 2020/7/31 8:55
12  * 与懒汉式线程不安全会有同样的问题,可能在多线程环境下创建多个实例。
13  */
14 public class Singleton5 {
15 
16     public static void main(String[] args) {
17         System.out.println("我是线程不安全的懒汉式2!!!");
18         Singleton instance = Singleton.getInstance();
19         Singleton instance2 = Singleton.getInstance();
20         System.out.println(instance == instance2);//true
21         System.out.println(instance.hashCode()==instance2.hashCode());//true
22     }
23 
24 }
25 
26 class Singleton{
27     private Singleton(){}
28 
29     private static Singleton instance;
30 
31     //提供一个静态公有方法,当时用到该方法时,才会创建instance。(懒汉式的核心)
32     public static Singleton getInstance(){
33         if (instance == null)
34 
35             synchronized (Singleton.class){
36             instance = new Singleton();}
37 
38         return instance;
39     }
40 }
View Code

6.双重检查

 1 package Singleton.Singletontest6;
 2 
 3 /**
 4  * @title: Singleton6
 5  * @Author yzhengy
 6  * @Date: 2020/7/31 9:09
 7  * @Question: 双重检查--推荐使用
 8  */
 9 public class Singleton6 {
10     public static void main(String[] args) {
11         System.out.println("我是双重检查");
12         Singleton instance = Singleton.getInstance();
13         Singleton instance2 = Singleton.getInstance();
14         System.out.println(instance == instance2);//true
15         System.out.println(instance.hashCode()==instance2.hashCode());//true
16     }
17 }
18 
19 /*
20  * @Date: 2020/7/31 9:16
21  * 线程安全;延迟加载;效率较高;
22  */
23 class Singleton{
24     private Singleton(){}
25 
26     private static volatile Singleton instance;
27 
28     public static Singleton getInstance(){
29         if (instance == null){
30             synchronized (Singleton.class){
31                 if (instance == null)
32                     instance = new Singleton();
33             }
34         }
35         return instance;
36     }
37 }
View Code

7.静态内部类

 1 package Singleton.Singletontest7;
 2 
 3 /**
 4  * @title: Singleton7
 5  * @Author yzhengy
 6  * @Date: 2020/7/31 9:18
 7  * @Question: 静态内部类--推荐使用
 8  */
 9 public class Singleton7 {
10     public static void main(String[] args) {
11         System.out.println("我是静态内部类");
12         Singleton instance = Singleton.getInstance();
13         Singleton instance2 = Singleton.getInstance();
14         System.out.println(instance == instance2);//true
15         System.out.println(instance.hashCode()==instance2.hashCode());//true
16     }
17 }
18 /*
19  * @Date: 2020/7/31 9:20
20  * 外部类被装载时,静态内部类并不会被装载。
21  * 当调用getInstance时才会使静态内部类被装载,而且只会装载一次,装载时线程安全。
22  * 优点:线程安全,利用静态内部类特点实现延迟加载,效率高。
23  */
24 class Singleton{
25     private Singleton(){}
26 
27     //静态内部类,该类中有一个静态属性Singleton
28     private static class SingletonInstance{
29         private final static Singleton INSTANCE = new Singleton();
30     }
31 
32     //提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
33     public static Singleton getInstance(){
34         return SingletonInstance.INSTANCE;
35     }
36 }
View Code

8.枚举

 1 package Singleton.Singletontest8;
 2 
 3 /**
 4  * @title: Singleton8
 5  * @Author yzhengy
 6  * @Date: 2020/7/31 9:30
 7  * @Question: 枚举--推荐使用
 8  */
 9 public class Singleton8 {
10     public static void main(String[] args) {
11         System.out.println("我是枚举");
12         Singleton instance = Singleton.INSTANCE;
13         Singleton instance2 = Singleton.INSTANCE;
14         System.out.println(instance == instance2);//true
15         System.out.println(instance.hashCode()==instance2.hashCode());//true
16 
17         instance.sayOK();
18     }
19 }
20 /*
21  * @Date: 2020/7/31 9:34
22  * 使用枚举可以实现单例
23  * 不仅可以避免多线程同步问题,还能防止反序列化重新创建新的对象。(其他方法则需要使用transient关键字)
24  * 可以防止反射攻击。
25  */
26 enum Singleton{
27     INSTANCE;
28     public void sayOK(){
29         System.out.println("ok");
30     }
31 }
View Code

 

posted @ 2020-07-31 10:06  10000_Hours  阅读(128)  评论(0编辑  收藏  举报