java设计模式-单例模式

模式导读:

单例模式:保证一个类只有一个实例,并且能够提供一个访问该实例的全局访问点。

优点:由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

参考类图:

代码实现:

常见的五种单例模式实现方式:

主要:

  饿汉式:线程安全,调用效率高,不能延时加载。

 1 package com.etc;
 2 
 3 //饿汉式单例模式,不可延时加载,调用效率高
 4 public class HungrySingleton {
 5     // 类初始化时立即加载这个对象,加载类时天然的是线程安全的
 6     private static HungrySingleton instance = new HungrySingleton();
 7 
 8     // 让构造器为 private,这样该类就不会被实例化
 9     private HungrySingleton() {
10     }
11 
12     // 获取唯一可用的对象,方法没有同步,调用效率高
13     public static HungrySingleton getInstance() {
14         return instance;
15     }
16 
17     public void showMessage() {
18         System.out.println("饿汉式单例模式测试输出:立即加载!");
19     }
20 }

 懒汉式:线程安全,调用效率不高,可以延时加载。

 1 package com.etc;
 2 //懒汉式单例模式
 3 public class LazySingleton {
 4     //类初始化时,不初始化对象,延时加载
 5     private static LazySingleton instance=null;
 6     //私有化构造器
 7     private LazySingleton() {
 8         
 9     }
10     //设置了方法同步,每次调用该方法都要同步,并发效率低,资源利用率高
11     public synchronized static LazySingleton getInstance() {
12         //当需要使用时再初始化类对象
13         if(instance==null) {
14             instance=new LazySingleton();
15         }
16         return instance;
17     }
18     public void showMessage() {
19         System.out.println("懒汉式单例模式测试输出:延时加载!");
20     }
21 }

其他:

 双重检测锁式:由于JVM底层内部模型原因,偶尔会出问题,不建议使用。

 1 package com.etc;
 2 //双重检测锁式单例模式
 3 public class DCClockSingleton {
 4 
 5     public static DCClockSingleton instance=null;
 6     //私有化构造器
 7     private DCClockSingleton() {
 8 
 9     }
10     //将同步内容下放到if内部,提高了执行的效率,不必每次获取对象都进行同步,只有第一次才同步创建了以后就不必同步
11     public static DCClockSingleton getInstance() {
12         if(instance ==null) {
13             DCClockSingleton ds;
14             //第一重检测锁
15             synchronized(DCClockSingleton.class) {
16                 ds=instance;
17                 if(ds==null) {
18                     //第二重检测锁
19                     synchronized(DCClockSingleton.class) {
20                         if(ds==null) {
21                             ds=new DCClockSingleton();
22                         }
23                     }
24                     instance=ds;
25                 }
26             }
27         }
28         return instance;
29     }
30     public void showMessage() {
31         System.out.println("双重检测锁单例模式测试输出:延时加载!");
32     }
33 }

  静态内部类式:线程安全,调用效率高,可以延时加载。

 1 package com.etc;
 2 //静态内部类单例模式
 3 public class StaticNativeClassSingleton {
 4     //私有化构造器
 5     private StaticNativeClassSingleton() {
 6     }
 7     //静态内部类,实现类的延时加载
 8     private static class InstanceSingleton{
 9         private static final StaticNativeClassSingleton instance=new StaticNativeClassSingleton();
10     }
11     //方法未同步,效率高
12     public static  StaticNativeClassSingleton getInstance() {
13         return InstanceSingleton.instance;
14     }
15     public void showMessage() {
16         System.out.println("静态内部类单例模式测试输出:延时加载!");
17         
18     }
19 }

  枚举单例:线程安全,调用效率高,不能延时加载。

1 package com.etc;
2 //枚举单例模式
3 public enum EnumSingleton {
4     //枚举元素本身就是代表单例对象
5     instance;
6     public void showMessage() {
7         System.out.println("枚举单例模式测试输出:立即加载!");
8     }
9 }

ps:测试类

 1 package com.etc;
 2 
 3 public class SingletonTest {
 4 
 5     public static void main(String[] args) {
 6         //饿汉式单例模式测试输出
 7         HungrySingleton hungry=HungrySingleton.getInstance();
 8         hungry.showMessage();
 9         //懒汉式单例模式测试输出
10         LazySingleton lazy=LazySingleton.getInstance();
11         lazy.showMessage();
12         //双重检测锁单例模式测试输出
13         DCClockSingleton dcclock=DCClockSingleton.getInstance();
14         dcclock.showMessage();
15         //静态内部类单例模式测试输出
16         StaticNativeClassSingleton sns=StaticNativeClassSingleton.getInstance();
17         sns.showMessage();
18         //枚举单例模式测试输出
19         EnumSingleton e=EnumSingleton.instance;
20         e.showMessage();
21         
22     }
23 }

效果截图:

单例模式优缺点:

优点:

1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
2、避免对资源的多重占用。

缺点:

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

适用场景:

1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

 

原文地址:https://www.cnblogs.com/weekstart/p/singleton.html