• Java学习笔记-单件模式


    来源于headfirst设计模式

    单例模式的性能指标:lazy(是否延迟实例化),线程安全

    一、延迟实例化,同步(synchronized)方法-->由于是单例更需要考虑处理问题需要考虑的同步问题,延迟实例化主要是面向资源敏感的对象

     1 public class Singleton {
     2 
     3     private static Singleton uniqueinstance;//唯一的实例变量
     4 
     5     private Singleton() {//私有的初始化方法
     6     }
     7 
     8     public static synchronized Singleton getInstance() {
     9     //实例的获取方法,将普通的初始化方法变为获得方法
    10         if (uniqueinstance== null) {
    11             uniqueinstance= new Singleton();//直接在类内部初始化
    12         }
    13         return instance;
    14     }
    15 }

    二、直接实例化(静态工厂方法)

     1 public class Singleton {
     2 
     3     private static Singleton uniqueInstance = new Singleton();
     4     //直接创建单例
     5     private Singleton() {
     6     }
     7 
     8     public static Singleton getInstance() {
     9 
    10         return uniqueInstance;
    11     }
    12 }

    三、双重检验加锁,双重检查锁定模式首先验证锁定条件(第一次检查),只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。-->用来减少并发系统中竞争和同步的开销。[http://zh.wikipedia.org/wiki/%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F]

    public class Singleton {
    
        private volatile static Singleton instance = null;//volatile变量
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
    
            if (instance == null) {//只有首次初始化时才用到了同步模块,避免了同步对资源的浪费
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    volatile变量的作用[参考:http://blog.csdn.net/orzorz/article/details/4319055]

    用在多线程,为了同步变量。在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。 
    一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。synchronized的优势在于其可以把方法或者代码块变为原子操作,而volatile无法。

     四、枚举单例,上面的方法都有一个问题就是反序列化,破坏了单例的特性,你可以去查询使用readResolve(),但比较麻烦,推荐使用Java的这个新特性——枚举类型。它具有内置的序列化支持和线程安全支持。

    public enum EasySingleton{

      INSTANCE;
    }

    在 java 垃圾回收中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。

    [http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html]

    五、各种优化

    /**
     * 基于内部类的单例模式  Lazy  线程安全
     * 优点:
     * 1、线程安全
     * 2、lazy
     * 缺点:
     * 1、待发现
     * 
     * @author laichendong
     * @since 2011-12-5
     */
    public class SingletonFive {
        
        /**
         * 内部类,用于实现lzay机制
    */
        private static class SingletonHolder{
            /** 单例变量  */
            private static SingletonFive instance = new SingletonFive();
        }
        
        /**
         * 私有化的构造方法,保证外部的类不能通过构造器来实例化。
    */
        private SingletonFive() {
            
        }
        
        /**
         * 获取单例对象实例
         * 
         * @return 单例对象
    */
        public static SingletonFive getInstance() {
            return SingletonHolder.instance;
        }
        
    }

    http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html

    这种方式利用静态内部类的优势,既是后实例化的又是线程安全的。

    引申阅读:http://jiangzhengjun.iteye.com/blog/652440

    http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

  • 相关阅读:
    HTML 5 全局属性
    微软build 2015
    写个程序登陆58同城
    工厂方法
    简单工厂
    System.Data.SQLite兼容32位和64位问题
    利用Socket实现的两个程序的通信
    最近的工作总结
    Canvas路径、描边、填充
    HTML5阴影与渐变
  • 原文地址:https://www.cnblogs.com/lance-/p/3553659.html
Copyright © 2020-2023  润新知