zoukankan      html  css  js  c++  java
  • 1.5(设计模式)单例模式

    单例模式提供了创建一个类唯一对象的方式。

    单例模式情况下,某一个类只有唯一实例,且该实例可以被其他所有对象引用。

    单例模式的关键点:

    1.构造器私有化

    2.实例对象静态化

    构造器私有化后,无法通过new来创建,只能通过该类提供的方法获取实例对象。

    对象静态化后可保证全局有效,使获取的对象始终是一个对象。

    单例模式的实现方法:

    1、懒汉式(线程不安全、延时加载)

    延时加载即在调用时才会加载。

    //懒汉式,非同步  线程不安全
    //由于其非同步,所以严格意义上来说不属于单例模式
    //在多线程下无法正常工作。
    
    
    class Singleton{ 
        private static Singleton singleton;
        private Singleton() {}
        public static Singleton getInstance() {
            if(singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
        
        public void printObject() {
            System.out.println(this);
        }
    }

    这种单例模式不适用于多线程情况。

    2、懒汉式(线程安全、延时加载)

    //线程安全,可以在多线程中使用,但效率低下。
    //
    //
    class Singleton{   // 懒汉式线程安全
        private static Singleton singleton;
        private Singleton() {}
        public synchronized static Singleton getInstance() {
            if(singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
        
        public void printObject() {
            System.out.println(this);
        }
    }

    这里通过synchronized关键字对其加锁,保证了在多线程情况下的安全,但是锁住整个方法效率较低。

    3、饿汉式(线程安全,非延时加载)

    即在初始化就完成加载,而不是在调用时完成加载。

    //饿汉式
    //类在加载的时候就实例化了,就算thread1和thread2同时获取它,
    //取到的是类加载时实例化的那个变量的值,所以说是线程安全的。
    //饿汉式缺点是类加载是就初始化对象,浪费内存。
    
    class Singleton{
        private static Singleton singleton = new Singleton();
        private Singleton() {}
        public static Singleton getInstance() {
            return singleton;
        }
        public void printObject() {
            System.out.println(this);
        }
        
    }

    饿汉式在类加载时就创建了对象,避免了多线程访问的并发问题。

    但其类加载时就需要实例化对象,消耗内存。

    4、双重校验锁(线程安全,延时加载)

    //双重校验锁
    //多线程下能保持高性能
    class Singleton{
        private volatile static Singleton singleton;
        private Singleton() {}
        public static Singleton getInstance() {
            if(singleton == null) {
                synchronized(Singleton.class) {  //此时锁住的是类
                    if(singleton == null)
                        singleton =  new Singleton();
                }
            }
            return singleton;
        } 
        public void printObject() {
            System.out.println(this);
        }
    }

    采用双检锁既保证了多线程下的安全性,又保持了较好的性能。

    因为当对象存在时,第一判空条件上没有添加synchronized,不会降低效率。

    后续创建对象实例部分才添加了synchronized关键字锁住了类,然后再判断对象是否为空,保证了安全性。

    5、登记式/静态内部类(线程安全、延时加载)

    class Singleton{
        private Singleton() {};
        //静态内部类
        private static class SingletonHolder{
            private static final Singleton singleton = new Singleton();
        }
        
        public static Singleton getInstance() {
            return SingletonHolder.singleton;
        }
        
        public void printObject() {
            System.out.println(this);
        }
    }

    静态内部类加载后并不会立刻加载内部的静态属性,只有外部调用内部类才会初始化静态属性,加载实例。

    这样既保证了多线程情况下的安全性,而且实现了延迟加载。

    参考资料:

    http://www.runoob.com/design-pattern/singleton-pattern.html

  • 相关阅读:
    Anroid自定义RatingBar,显示半个(小数个)的stepSize时,变为整数个的问题
    浅谈Java对象回收的三种方式
    今天为火狐社区做了点小小的共享,开心一下~~
    解决mac的日历问题:服务器响应一个错误
    android.content.res.Resources$NotFoundException:String resource ID #ffffffff
    Android 读写文件的第一种方式(文件方式)
    ListView的性能提升
    C++中的回调函数实现,sink方式
    技巧:Activity收集器
    技巧:知晓当前在哪个Activity
  • 原文地址:https://www.cnblogs.com/huang-changfan/p/10736902.html
Copyright © 2011-2022 走看看