zoukankan      html  css  js  c++  java
  • Java中的单例模式

    前言

      Double-Check虽然是一种巧妙的程序设计方式,但是有可能会抛出空指针的异常,这一切均是由于JVM在运行时指令重排序所导致的,而volatile关键字则可以防止这种重排序的发生。满足多线程程序下的单例、懒加载以及获取实例的高效性。可以这样实现:

    private volatile static Singleton instance = null;

      volatile以后研究,这里不搞了。

    Holder方式

      Holder方式完全是借助了类加载的特点。先看看怎样去写,然后简单总结下好处。

     1 public class Singleton {
     2 
     3     // 实例变量
     4     private byte[] data = new byte[1024];
     5     
     6     private Singleton() {
     7         
     8     }
     9     
    10     // 静态内部类中持有Singleton的实例,并且可直接被初始化
    11     private static class Holder {
    12         private static Singleton instance = new Singleton();
    13     }
    14     
    15     // 调用getInstance方法,实际上是获得Holder的instance静态属性
    16     public static Singleton getInstance() {
    17         return Holder.instance;
    18     }
    19 }

      在Singleton类中并没有instance的静态成员,而是将其放到了静态的内部类Holder之中,所以Singleton类的初始化过程中并不会创建Singleton实例。在Holder类中定义了Singleton的静态变量,并且直接进行了初始化,当Holder被主动引用的时候则会创建Singleton的实例,Singleton实例的创建过程在Java程序编译时期收集至<clinit>()方法中,这个方法又是同步方法,同步方法保证了内存的可见性、JVM指令的顺序性和原子性。Holder方式是目前使用比较广泛的设计之一。

      关于类的主动引用和被动引用,类的初始化过程后面会专门来研究,这里不介绍。

    枚举方式

      首先,关于枚举有几点需要事先声明。

    1. 枚举类型不允许被继承
    2. 线程安全且只能被实例化一次
    3. 枚举类型不能被懒加载
     1 public enum SingletonEnum {
     2     
     3     INSTANCE;
     4     
     5     // 实例变量
     6     private byte[] data = new byte[1024];
     7 
     8     SingletonEnum() {
     9         System.out.println("new SingletonEnum()");
    10     }
    11     
    12     public static void method() {
    13         // 调用这个方法则会主动使用SingletonEnum,INSTANCE将会被实例化
    14     }
    15     
    16     public static SingletonEnum getInstance() {
    17         return INSTANCE;
    18     }
    19 }

    枚举方式改造+懒加载

     1 public class Singleton {
     2 
     3     // 实例变量
     4     private byte[] data = new byte[1024];
     5 
     6     private Singleton() {
     7 
     8     }
     9 
    10     // 使用枚举充当holder
    11     private enum EnumHolder {
    12         
    13         INSTANCE;
    14         
    15         private Singleton instance;
    16         
    17         EnumHolder() {
    18             this.instance = new Singleton();
    19         }
    20         
    21         private Singleton getSingleton() {
    22             return instance;
    23         }
    24     }
    25 
    26     public static Singleton getInstance() {
    27         return EnumHolder.INSTANCE.getSingleton();
    28     }
    29 
    30 }

    总结

    1. 控制资源的使用,通过线程同步来控制资源的并发访问
    2. 控制实例的产生,以达到节约资源的目的
    3. 在单例类中定义一些全局变量,多线程可以同时访问此全局变量,达到数据共享的目的。
  • 相关阅读:
    MISP版本嵌入式QT编译时出现mips-linux-gcc command not found
    数据传输对象(DTO)介绍及各类型实体比较
    signalR例子
    WebAPI GET和POST请求的几种方式
    github教程
    Asp.net MVC + EF + Spring.Net 项目实践3
    SpringMVC
    SignalR
    SignalR的实时高频通讯
    开发视频教程
  • 原文地址:https://www.cnblogs.com/sunl123/p/11087135.html
Copyright © 2011-2022 走看看