• Java设计模式—单例模式


    Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。

    核心知识点如下:

    (1) 将采用单例设计模式的类的构造方法私有化(采用private修饰)。

    (2) 在其内部产生该类的实例化对象,并将其封装成private static类型。

    (3) 定义一个静态方法返回该类的实例。

    一:饿汉模式

    优点是:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题;
    缺点是:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,
    这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存

    package cn.design.singleton;
    
    /**
     * 饿汉模式
     * 优点是:写起来比较简单,而且不存在多线程同步问题,避免了synchronized所造成的性能问题;
     * 缺点是:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间
     * 从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
     * @author 翎野君
     *
     */
    public class SingletonTest {
        
        //将构造方法私有化,使得外部不可以访问
        //只可以从定义的getInstance方法获取实例化对象
        //防止外部通过new SingleTonTest()实例化对象
        private SingletonTest(){
            
        }
        /**
         * instance外部不可以直接访问,随着类加载而加载
         * static静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配
         * final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
         */
        private static final SingletonTest instance=new SingletonTest();
        //静态方法,不随对象的不同而改变
        //返回上面定义的instance对象
        public static SingletonTest getInstance(){
            return instance;
        }
        public static void main(String[] args) {
            //在当前类下是可以访问的但是其他类不可以访问private变量
            SingletonTest st=new SingletonTest();
            //其他类中这样获取
            SingletonTest st1=SingletonTest.getInstance();
        }
    }

    二:饱汉模式

    优点是:写起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存;
    缺点是:并发环境下很可能出现多个SingletonTest实例

    package cn.design.singleton;
    
    public class SingletonTest1 {
        
        //将构造方法私有化防止外部通过new SingleTest1()获取对象
        private SingletonTest1(){
            
        }
        //饱汉模式就是吃饱了,不着急等初始化对象的时候在获取一个唯一实例
        //没有加final关键字,如果加上的话当即就要赋值
        //而饱汉模式要求动态调用的时候创建唯一实例
        private static SingletonTest1 instance;
        //定义一个静态方法等待调用的时候在对其进行对象初始化(多线程时无法保证只有一个对象)
        public static SingletonTest1 getInstance(){
            if(instance==null){
                instance=new SingletonTest1();
            }
            return instance;
        }
        
        public static void main(String[] args) {
            SingletonTest1 st=SingletonTest1.getInstance();
            System.out.println(st);
        }
    }

    三:饱汉模式的优化

    优点是:使用synchronized关键字避免多线程访问时,出现多个SingletonTest实例。
    缺点是:同步方法频繁调用时,效率略低。

    package cn.design.singleton;
    
    /**
     * 优化饱汉模式
     * 优点:加锁防止多线程访问时出现多个实例的问题
     * 缺点:同步方法频繁调用时,效率略低。
     * @author 翎野君
     *
     */
    public class SingletonTest2 {
        
        private SingletonTest2(){
            
        }
        private static SingletonTest2 instance;
        //定义一个静态方法,调用时进行初始化
        //加上一把锁synchronized之后防止出现多线程并发调用时出现多个实例的问题
        public synchronized static SingletonTest2 getInstance(){
            if(instance==null){
                instance=new SingletonTest2();
            }
            return instance;
        }
    }

    四:最优方案(不考虑反射的情况)

    方法四为单例模式的最佳实现。内存占用地,效率高,线程安全,多线程操作原子性。

    package cn.design.singleton;
    
    public class SingletonTest3 {
    
        private SingletonTest3(){
            
        }
        //使用volatile保证了多线程访问时instance变量的可见性,
        //避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用
        //使用volatile保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用
        private static volatile SingletonTest3 instance;
        
        public static SingletonTest3 getInstance(){
            if(instance==null){
                ////同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建)
                synchronized (SingletonTest3.class) {
                    System.out.println(SingletonTest3.class);
                    instance=new SingletonTest3();
                }
            }
            return instance;
        }
        public static void main(String[] args) {
            SingletonTest3 st=SingletonTest3.getInstance();
            
        }
    }
  • 相关阅读:
    调用AsyncTask的excute方法不能立即执行程序的原因分析及改善方案
    辅助
    目录检索
    高斯消元法
    树套树
    珂朵莉树
    卢卡斯定理
    中国剩余定理
    数论基础
    网络流基础
  • 原文地址:https://www.cnblogs.com/lingyejun/p/7116233.html
Copyright © 2020-2023  润新知