zoukankan      html  css  js  c++  java
  • JAVA设计模式——单例模式

    英文名:Singleton Pattern。英文原话:Ensure a class has only one instance,and provide a global point of access to it。

    单例模式的主要作用是确保一个类只有一个实例。

    一、实现方式

    1.静态内部类

    这是最好的实现方式,废话不多说,直接上代码。

    要点:私有的构造方法,保证外界无法直接实例化。一个内部静态类来进行实例化,这样能达到延迟初始化的效果。并且有 classloader 机制来保证初始化 instance 时只有一个线程。

    public class Singleton {
        //构造方法私有,保证外界无法直接实例化
        private Singleton(){}
    
        public static Singleton getInstance(){
            return SingletonInstance.instance;
        }
    
        private static class SingletonInstance{
            static Singleton instance = new Singleton();
        }
    }

    2.饿汉模式

    public class HungrySingleton {
        private HungrySingleton() {}
    
        private static HungrySingleton instance = new HungrySingleton();
    
        private static HungrySingleton getInstance() {
            return instance;
        }
    }

    饿汉模式是在类加载的时候,就进行对象实例化。缺点就是如果这个类里面有一个静态方法,代码里先使用了这个静态方法,这时候就会完成实例化。这时候可能是还用不到这个实例的,就会造成浪费。就这一个问题,所以结合具体情况,饿汉模式使用也没有大问题。

    3.懒汉模式

    public class LazySingleton {
        private static LazySingleton instance;
    
        private LazySingleton() {
        }
    
        public static LazySingleton getInstance() {
            if (instance == null) {
                instance = new LazySingleton();
            }
            return instance;
        }
    }

    懒汉模式是在第一次引用类时,才进行对象实例化。这种方式存在的问题是线程安全问题,就是多个线程同时去获取实例的时候,可能会产生多个实例。

    讲到线程安全问题,通常就会想到synchronized加一个锁来保证线程安全问题,没错,如下图,可以这样来保证线程安全

    public class OneCheckLazySingleton {
        private static OneCheckLazySingleton instance;
    
        private OneCheckLazySingleton() {
        }
    
        public static synchronized OneCheckLazySingleton getInstance() {
            if (instance == null) {
                instance = new OneCheckLazySingleton();
            }
            return instance;
        }
    }

    但是这样每次去获取实例的时候,都会去走一遍这个锁,其实在实例已经创建过后,就不会有线程安全问题了。所以有了改进版,双重检查锁,如下

    public class DoubleCheckLazySingleton {
        private volatile static DoubleCheckLazySingleton singleton;
    
        private DoubleCheckLazySingleton() {
        }
    
        public static DoubleCheckLazySingleton getSingleton() {
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new DoubleCheckLazySingleton();
                    }
                }
            }
            return singleton;
        }
    }

    这样在实例已经创建后,再去获取就不会走锁了。注意这里的volatile关键字,volatile禁止了JVM自动的指令重排序优化,是在jdk1.5及以后才有的。这样,这种方式也是没有问题的了,就是代码相对复杂。

    二、具体应用

    先讲一个概念,有状态的类和无状态的类。

    有状态的类:类里面有成员变量,而且成员变量是会变的。

    无状态的类:类里面没有成员变量,或者有成员变量但是不可变的。

    无状态的类才适合使用单例模式,一些连接池,比如连接redis的jedis工具的JedisPool 可以使用单例。

    再讲一下分布式下的情况,分布式时,就是有多个jvm。一开始想到这个问题时,我还认为在分布式情况下会有问题,因为在一个jvm下有一个单例,整个系统不是只有一个实例了。 但仔细想了一下,因为是无状态的类,对整个系统是没有问题的。

    好了,差不多就这些。谢谢阅读~

  • 相关阅读:
    反调试:ZwQueryInformationProcess
    反调试:检测类名与标题名
    对某个区间操作(sort,stable_sort,parital_sort,parital_sort_copy,nth_element,is_sorted)
    数值算法(accumluate,inner_product,partial_sum,adjacent_difference,power,itoa)
    随机重拍与抽样(random_shuffle,random_sample,random_sample_n)
    分割(partition,stable_partition)
    子序列匹配(search,search_n,adjcent_find,find,find_if,find_first_of,find_end)
    MySQL管理实务处理
    MySQL触发器
    MySQL使用游标
  • 原文地址:https://www.cnblogs.com/shanejim/p/9961018.html
Copyright © 2011-2022 走看看