精华内容
下载资源
问答
  • 懒汉式 懒汉式经典写法 public class Singleton { //在类中定义一个私有的静态的 Singleton 变量,不进行初始化赋值 private static Singleton singleton; //私有空参数构造方法,不让用户直接创建对象 private ...

    单例模式介绍:

    单例模式指的是,保证一个类只有一个实例,并且提供一个全局可以访问的入口。举个例子,这就好比是“分身术”,但是每个“分身”其实都对应同一个“真身”。

    使用单例模式的理由/好处:

    其中一个理由,那就是为了节省内存、节省计算。很多情况下,我们只需要一个实例就够了,如果出现了更多的实例,反而属于浪费。举个例子,我们就拿一个初始化比较耗时的类来说:

    public class ExpensiveResource {
    
        public ExpensiveResource() {
    
            field1 = // 查询数据库
    
            field2 = // 然后对查到的数据做大量计算
    
            field3 = // 加密、压缩等耗时操作
    
        }
    
    }
    

    上面的类在进行构造的时候,需要查询数据库并对查到的数据做大量计算,所以在第一次构造时,我们花了很多时间来初始化这个对象。但是假设我们数据库里的数据是不变的,并把这个对象保存在了内存中,那么以后就用同一个实例了,如果每次都重新生成新的实例,实在是没必要。

    第二个理由,那就是为了保证结果的正确。比如我们需要一个全局的计数器,用来统计人数,那么如果有多个实例,反而会造成混乱。

    另外呢,就是为了方便管理。很多工具类,我们只需要一个实例,那么我们通过统一的入口,比如通过 getInstance 方法去获取这个单例是很方便的,太多实例不但没有帮助,反而会让人眼花缭乱。

    单例模式有哪些适用场景:

    无状态的工具类:

    比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们就只需要一个实例对象。

    全局信息类:

    比如我们在一个类上记录网站的访问次数,并且不希望有的访问被记录在对象 A 上,有的却被记录在对象 B 上,这时候我们就可以让这个类成为单例,需要计数的时候拿出来用即可。

    单例模式的几种实现方式:

    饿汉式

    饿汉式经典写法

    public class Singleton {
    	//定义一个私有的静态的 Singleton 变量,并进行初始化赋值(创建一个对象给变量赋值)
        private static Singleton singleton = new Singleton();
        //私有空参数构造方法,不让用户直接创建对象
        private Singleton(){}
        //定义一个公共的静态方法,返回 Singleton 对象
        public static Singleton getInstance(){
            return singleton;
        }
    }
    

    特点:
    由 JVM 的类加载机制保证了线程安全,因为在类被加载时便会把实例生成出来,避免了线程同步的问题,但同样也是其缺点,假设我们最终没有使用到这个实例的话,便会造成不必要的开销。

    下面我们再来看下饿汉式的变种——静态代码块形式

    饿汉式变种写法:静态代码块形式

    public class Singleton {
    
        private static Singleton singleton;
        
        static {
    
            singleton = new Singleton();
    
        }
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            return singleton;
        }
    
    }
    

    特点
    优缺点和经典写法一样,只是写法有些不同。

    懒汉式

    懒汉式经典写法

    public class Singleton {
    	//在类中定义一个私有的静态的 Singleton 变量,不进行初始化赋值
        private static Singleton singleton;
    	//私有空参数构造方法,不让用户直接创建对象
        private Singleton() {}
    	//在类中定义一个公共的静态成员方法,返回 Singleton 对象,保证无论调用多少次方法,只返回一个对象
        public static Singleton getInstance() {
    
            if (singleton == null) {
    
                singleton = new Singleton();
    
            }
    
            return singleton;
    
        }
    
    }
    
    

    特点:

    这种写法的优点在于,只有在 getInstance 方法被调用的时候,才会去进行实例化,所以不会造成资源浪费,但是在创建的过程中,并没有考虑到线程安全问题,如果有两个线程同时执行 getInstance 方法,就可能会创建多个实例。所以这里需要注意,不能使用这种方式,这是错误的写法

    为了避免发生线程安全问题,我们可以对前面的写法进行升级,那么线程安全的懒汉式的写法是怎样的呢。

    懒汉式线程安全写法:第一种

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

    特点:
    我们在 getInstance 方法上加了 synchronized 关键字,保证同一时刻最多只有一个线程能执行该方法,这样就解决了线程安全问题。但是这种写法的缺点也很明显:如果有多个线程同时获取实例,那他们不得不进行排队,多个线程不能同时访问,然而这在大多数情况下是没有必要的。

    懒汉式线程安全写法:第二种

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

    特点:
    这种写法是错误的。将synchronized 放在getInstance方法内部,它的本意是想缩小同步的范围,但是从实际效果来看反而得不偿失。因为假设有多个线程同时通过了 if 判断,那么依然会产生多个实例,这就破坏了单例模式。

    所以,为了解决这个问题,在这基础上就有了“双重检查模式”。

    懒汉式线程安全写法:第三种

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

    特点:
    对singleton对象添加volatile,将
    这种写法的优点就是不仅做到了延迟加载,而且是线程安全的,同时也避免了过多的同步环节。推荐这种写法。我们重点来看一下 getInstance 方法,这里面有两层 if 判空,下面我们分别来看一下每个 if 的作用。

    这里涉及到一个常见的问题,面试官可能会问你,“为什么要 double-check?去掉第二次的 check 行不行?”这时你需要考虑这样一种情况,有两个线程同时调用 getInstance 方法,并且由于 singleton 是空的 ,所以两个线程都可以通过第一个 if。

    然后就遇到了 synchronized 锁的保护,假设线程 1 先抢到锁,并进入了第二个 if ,那么线程 1 就会创建新实例,然后退出 synchronized 代码块。接着才会轮到线程 2 进入 synchronized 代码块,并进入第二层 if,此时线程 2 会发现 singleton 已经不为 null,所以直接退出 synchronized 代码块,这样就保证了没有创建多个实例。假设没有第二层 if,那么线程 2 也可能会创建一个新实例,这样就破坏了单例,所以第二层 if 肯定是需要的。

    而对于第一个 check 而言,如果去掉它,那么所有线程都只能串行执行,效率低下,所以两个 check 都是需要保留。

    相信你可能看到了,我们在双重检查模式中,给 singleton 这个对象加了 volatile 关键字,那为什么要用 volatile 呢?这是因为 new 一个对象的过程,其实并不是原子的,至少包括以下这 3 个步骤:

    • 1、给 singleton 对象分配内存空间;
    • 2、调用 Singleton 的构造函数等,来进行初始化;
    • 3、把 singleton 对象指向在第一步中分配的内存空间,而在执行完这步之后,singleton 对象就不再是 null 了。

    这里需要留意一下这 3 个步骤的顺序,因为存在重排序,所以上面所说的三个步骤的顺序,并不是固定的。虽然看起来是 1-2-3 的顺序,但是在实际执行时,也可能发生 1-3-2 的情况,也就是说,先把 singleton 对象指向在第一步中分配的内存空间,再调用 Singleton 的构造函数。

    如果发生了 1-3-2 的情况,线程 1 首先执行新建实例的第一步,也就是分配单例对象的内存空间,然后线程 1 因为被重排序,所以去执行了新建实例的第三步,也就是把 singleton 指向之前的内存地址,在这之后对象不是 null,可是这时第 2 步并没有执行。假设这时线程 2 进入 getInstance 方法,由于这时 singleton 已经不是 null 了,所以会通过第一重检查并直接返回 singleton 对象并使用,但其实这时的 singleton 并没有完成初始化,所以使用这个实例的时候会报错。

    最后,线程 1“姗姗来迟”,才开始执行新建实例的第二步——初始化对象,可是这时的初始化已经晚了,因为前面已经报错了。

    到这里关于“为什么要用 volatile”问题就讲完了,使用 volatile 的意义,我认为主要在于呢,它可以防止刚讲到的重排序的发生,也就避免了拿到没完成初始化的对象。

    接下来要讲到的这种方式,静态内部类的写法,利用了类装载时由 JVM 所保证的单线程原则,进而保证了线程安全。

    懒汉式线程安全写法:第四种

    public class Singleton {
    
    
        private Singleton() {}
    
        private static class SingletonInstance {
    
            private static final Singleton singleton = new Singleton();
    
        }
     
        public static Singleton getInstance() {
    
            return SingletonInstance.singleton;
    
        }
    
    }
    

    相比于饿汉式在类加载时就完成实例化,这种静态内部类的写法并不会有这个问题,这种写法只有在调用 getInstance 方法时,才会进一步完成内部类的 singleton 的实例化,所以不存在内存浪费的问题。

    这里简单做个小总结,静态内部类写法与双重检查模式的优点一样,都是避免了线程不安全的问题,并且延迟加载,效率高。

    可以看出,静态内部类和双重检查的写法都是不错的写法,但是它们不能防止被反序列化生成多个实例,那有没有更好的写法呢?最后我们来看枚举方式的写法。

    枚举单例模式

    枚举单例模式的写法

    public enum Singleton {
    
        INSTANCE;
    
        public void myMethod() { 
    
        }
    
    }
    

    前面我们讲了饿汉式、懒汉式、双重检查、静态内部类、枚举这 5 种写法,有了这么多方法可以实现单例,这时你可能会问了,那我该怎么选择,用哪种单例的实现方案最好呢?

    Joshua Bloch(约书亚·布洛克)在《Effective Java》一书中明确表达过一个观点:“使用枚举实现单例的方法,虽然还没有被广泛采用,但是单元素的枚举类型已经成为了实现 Singleton 的最佳方法。”

    为什么他会更为推崇枚举模式的单例呢?这就不得不回到枚举写法的优点上来说了,枚举写法的优点有这么几个:

    首先就是写法简单枚举的写法不需要我们自己考虑懒加载、线程安全等问题。同时,代码也比较“短小精悍”,比任何其他的写法都更简洁,很优雅。

    第二个优点是线程安全有保障,枚举类的本质也是一个 Java 类,但是它的枚举值会在枚举类被加载时完成初始化,所以依然是由 JVM 帮我们保证了线程安全。

    前面几种实现单例的方式,其实是存在隐患的,那就是可能被反序列化生成新对象,产生多个实例,从而破坏了单例模式。接下来要说的枚举写法的第 3 个优点,它恰恰解决了这些问题。

    对 Java 官方文档中的相关规定翻译如下:“枚举常量的序列化方式不同于普通的可序列化或可外部化对象。枚举常量的序列化形式仅由其名称组成;该常量的字段值不存在于表单中。要序列化枚举常量,ObjectOutputStream 将写入枚举常量的 name 方法返回的值。要反序列化枚举常量,ObjectInputStream 从流中读取常量名称;然后,通过调用 java.lang.Enum.valueOf 方法获得反序列化常量,并将常量的枚举类型和收到的常量名称作为参数传递。”

    也就是说,对于枚举类而言,反序列化的时候,会根据名字来找到对应的枚举对象,而不是创建新的对象,所以这就防止了反序列化导致的单例破坏问题的出现。

    对于通过反射破坏单例而言,枚举类同样有防御措施。反射在通过 newInstance 创建对象时,会检查这个类是否是枚举类,如果是,就抛出 IllegalArgumentException(“Cannot reflectively create enum objects”) 异常,反射创建对象失败。

    可以看出,枚举这种方式,能够防止序列化和反射破坏单例,在这一点上,与其他的实现方式比,有很大的优势。安全问题不容小视,一旦生成了多个实例,单例模式就彻底没用了。

    总结:

    最后我来总结一下。今天我讲解了单例模式什么是,它的作用、用途,以及 5 种经典写法,其中包含了饿汉式、懒汉式、双重检查方式、静态内部类方式和枚举的方式,最后我们还经过对比,看到枚举方式在写法、线程安全,以及避免序列化、反射攻击上,都有优势。

    这里也跟大家强调一下,如果使用线程不安全的错误的写法,在并发情况下可能产生多个实例,那么不仅会影响性能,更可能造成数据错误等严重后果。

    如果是在面试中遇到这个问题,那么你可以从一开始的饿汉式、懒汉式说起,一步步分析每种写法的优缺点,并对写法进行演进,然后重点讲一下双重检查模式为什么需要两次检查,以及为什么需要 volatile 关键字,最后再说到枚举类写法的优点和背后的原理,相信这一定会为你的面试加分。

    另外在工作中,要是遇到了全局信息类、无状态工具类等场景的时候,推荐使用枚举的写法来实现单例模式。

    展开全文
  • 单例设计模式(懒汉式与饿汉式以及懒汉式存在的问题) 学习内容: 单例设计模式: 核心思想:就是这个类,在程序的任何其他模块中,获取它的对象时,拿到的永远是同一个对象。 单例模式有两种写法:懒汉式和饿汉式...

    学习目标:

    单例设计模式(懒汉式与饿汉式以及懒汉式存在的问题)

    学习内容:

    	单例设计模式: 核心思想:就是这个类,在程序的任何其他模块中,获取它的对象时,拿到的永远是同一个对象。
    	单例模式有两种写法:懒汉式和饿汉式。
    	懒汉式:若为空,则创建一个;若不为空,则直接返回。
    
    public class ProductDb {
    	public HashMap<String, String> pMap = new HashMap<>();
    
    	static ProductDb pdb = null;
    
    	private ProductDb() {
    
    	}
    
    	
    	  public static synchronized ProductDb getProductDb() {
    	  
    	  if(pdb==null) { 
    	  pdb = new ProductDb(); 
    	  } 
    	  return pdb;
    	  
    	  }
    	 
    

    饿汉式:先创建一个,别人调用的时候都返回这一个。

    public class ProductDb2 {
    	public HashMap<String, String> pMap = new HashMap<>();
    	static ProductDb2 pdb = new ProductDb2();
    
    	private ProductDb2() {
    	}
    	
    	public static ProductDb2 getProductDb() {
    		
    		return pdb;
    	}
    }
    
    

    懒汉式存在问题:判断是否为空以及创建一个新的对象并非原子操作。若用多线程来操作可能会同时创建多个新的对象,需要加锁。

    Public class ProductDb {
    	public HashMap<String,String> pMap=new HashMap<>();
    	static ProductDb pdb=null;
    	private Product() {  //构造方法要为私有
    	}
    	public static ProductDb getProductDb(){
    		if(pdb==null){
    			synchronized(pdb){
    				if(pdb==null){
    					pdb=new ProductDb();
    				}
    			}
    		}
    		return pdb;
    	}
    }
    
    展开全文
  • 所谓“懒汉式”与“饿汉式”的区别,是在与建立单例对象的时间的不同。 “懒汉式”是在你真正用到的时候才去建这个单例对象: 比如:有个单例对象 public class Singleton{ private Singleton(){} private static ...

    所谓“懒汉式”与“饿汉式”的区别,是在与建立单例对象的时间的不同。

    “懒汉式”是在你真正用到的时候才去建这个单例对象:

    比如:有个单例对象
    public class Singleton{
    private Singleton(){}
    private static Singleton singleton = null; //不建立对象
    public static synchronized Singleton getInstance(){
    if(singleton == null) { //先判断是否为空
    singleton = new Singleton (); //懒汉式做法
    }
    return singleton ;
    }
    }

    “饿汉式”是在不管你用的用不上,一开始就建立这个单例对象:比如:有个单例对象

    public class Singleton{
    public Singleton(){}
    private static Singleton singleton = new Singleton(); //建立对象
    public static Singleton getInstance(){
    return singleton ;//直接返回单例对象 }}
    它有以下几个要素:

    私有的构造方法
    指向自己实例的私有静态引用
    以自己实例为返回值的静态的公有的方法

    优缺点

    饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。
    懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。

    从实现方式来讲他们最大的区别就是懒汉式是延时加载,他是在需要的时候才创建对象
    而饿汉式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题
    写法简单明了,能用则用。真正用到的时候才去建这个单例对象,“饿汉式”是在不管用不用得上,一开始就建立这个单例对象。

    展开全文
  • 2.单例模式之懒汉式

    2021-01-15 12:22:23
    下面为三种懒汉式单例实现方式: 第一种:普通实现 1.不加锁,存在线程安全问题 package com.going.design.singleton.lazy; /** * Created by renxf on 2021/1/2 */ public class LazySinglton { private ...

    下面为三种懒汉式单例实现方式:

    第一种:普通实现

    1.不加锁,存在线程安全问题

    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     */
    public class LazySinglton {
        private static LazySinglton lazy = null;
    
        private LazySinglton(){};
    
        //此处存在线程安全问题
        public static  LazySinglton getInstance(){
            if(lazy == null){
                lazy = new LazySinglton();
            }
            return lazy;
        }
    }
    
    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     */
    public class TestLazy {
        public static void main(String[] args) {
    
            System.out.println("单线程测试");
            System.out.println(LazySinglton.getInstance());
            System.out.println(LazySinglton.getInstance());
            System.out.println(LazySinglton.getInstance());
        }
    
    }

    测试结果:获取到的对象为同一对象

    下面进行多线程调试测试:

    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     */
    public class TestLazy {
        public static void main(String[] args) {
    
    //        System.out.println("单线程测试");
    //        System.out.println(LazySinglton.getInstance());
    //        System.out.println(LazySinglton.getInstance());
    //        System.out.println(LazySinglton.getInstance());
    
            System.out.println("多线程测试");
            Thread t1 = new Thread(new ExectorThread());
            Thread t2 = new Thread(new ExectorThread());
            t1.start();
            t2.start();
            System.out.println("Exector End");
        }
    
    }
    
    class ExectorThread implements Runnable{
    
        @Override
        public void run() {
            LazySinglton lazySinglton = LazySinglton.getInstance();
            System.out.println(Thread.currentThread().getName()+":"+lazySinglton);
        }
    }

    测试结果:当两线程同时进入到if条件中,两个线程一先一后分别创建对象,便产生两个对象,有悖单例。

    2.使用synchronized 加锁

    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     */
    public class LazySinglton {
        private static LazySinglton lazy = null;
    
        private LazySinglton(){};
    
        // synchronized防止线程安全
        public static synchronized LazySinglton getInstance(){ 
            if(lazy == null){
                lazy = new LazySinglton();
            }
            return lazy;
        }
    }
    

    测试结果:当Thread0进入方法体中,Thread1的状态为MONITOR(监听状态,一旦Thread0释放锁之后便马上进入,此时lazy不为null),最终得到的对象为同一对象。

    分析:虽然JDK1.6之后对synchronized性能优化了不少,但还是存在性能问题,于是继续。。

    第二种:使用双重检查锁

    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     */
    public class LazyDoubleCheckSingleton {
        private static volatile LazyDoubleCheckSingleton lazy = null; //volatile解决重排序
    
        private LazyDoubleCheckSingleton(){};
    
        public static LazyDoubleCheckSingleton getInstance(){
            if(lazy == null){
                // 线程安全:双重检查锁(同步代码块)
                synchronized (LazyDoubleCheckSingleton.class){// why not class
                    if(lazy == null){
                    lazy = new LazyDoubleCheckSingleton();
                    // 指令重排序问题 使用volatile
                    // 1.分配内存给这个对象
                    // 2.初始化对象
                    // 3.将初始化的对象和内存地址建立联系
                    // 4.用户初次访问
                }
            }
            }
            return lazy;
        }
    
    }
    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     */
    public class TestLazyDoubleCheck {
        public static void main(String[] args) {
            Thread t1 = new Thread(new ExectorThread2());
            Thread t2 = new Thread(new ExectorThread2());
    
            t1.start();
            t2.start();
        }
    }
    
    class ExectorThread2 implements  Runnable{
        @Override
        public void run() {
            LazyDoubleCheckSingleton lazy = LazyDoubleCheckSingleton.getInstance();
            System.out.println(Thread.currentThread().getName()+":"+lazy);
        }
    }

    分析:为什么使用双重检查锁?第一次空对象检查为确保空对象,而非空对象则不需要同步,空对象的线程进入同步代码块;如果不加第二次空对象检查,两个线程同时进入代码块,将会创建两个实例化对象。

    第三种:使用静态内部类

    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     * 使用静态内部类,性能最优
     */
    public class LazyInnerClassSingleton {
        //虽然构造方法私有了,但是逃不过反射的法眼
        private LazyInnerClassSingleton(){};
    
        // 懒汉式单例
        // LazyHoler里面的逻辑需等外部方法调用时候才执行
        // 巧妙运用了内部类的特性
        // JVM底层逻辑,完美避免了线程安全问题
        public static final LazyInnerClassSingleton getInstance(){
            return LazyHoler.LAZY;
        }
    
        public static class LazyHoler{
            private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
        }
    }
    

    下面以此为例来测试通过反射来破坏单例

    package com.going.design.singleton.lazy;
    
    import java.lang.reflect.Constructor;
    
    /**
     * Created by renxf on 2021/1/2
     * 反射尝试破坏单例
     */
    public class TestLazyInnerClassSingleton {
        public static void main(String[] args) {
            try{
                // 不走寻常路,破坏了单例
                Class<?> clazz = Class.forName("com.going.design.singleton.lazy.LazyInnerClassSingleton");
                Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
                declaredConstructor.setAccessible(true);
    
                Object o1 = declaredConstructor.newInstance();
                Object o2 = LazyInnerClassSingleton.getInstance();
                System.out.println(o1 == o2);
                
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    

    执行结果为:false,为防止调用者反射破坏,可以这么来写:

    package com.going.design.singleton.lazy;
    
    /**
     * Created by renxf on 2021/1/2
     * 单例最牛逼的实现方法,使用静态内部类,性能最优
     */
    public class LazyInnerClassSingleton {
        //虽然构造方法私有了,但是逃不过反射的法眼
        private LazyInnerClassSingleton(){
            // 防止调用者反射攻击; 
            if(LazyHoler.LAZY != null){
                throw new RuntimeException("禁止创建多个实例!"); // 其他写法也可加上
            }
        };
    
        // 懒汉式单例
        // LazyHoler里面的逻辑需等外部方法调用时候才执行
        // 巧妙运用了内部类的特性
        // JVM底层逻辑,完美避免了线程安全问题
        public static final LazyInnerClassSingleton getInstance(){
            return LazyHoler.LAZY;
        }
    
        public static class LazyHoler{
            private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
        }
    }
    

    测试结果:

    分析:静态内部类相对来说更优,LazyHoler里面的逻辑需等外部方法调用时候才执行,所以也属于懒汉式,巧妙运用了内部类的特性,JVM底层逻辑,完美避免了线程安全问题,

    同时也演示并且防止了反射破坏,但开发者依然可以利用序列化方式来创建对象,下一篇写反序列化时创建对象破坏单例。

     

    展开全文
  • Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。单例模式有以下特点:1、单例类只能有一个实例。2、单例类必须自己创建自己的唯一实例。3、...
  • 什么是Java单例设计模式?1.所谓类的单例设计模式就是在软件的设计的过程之中,保证某个类的对象只能被...单例设计模式——饿汉:在类被加载的时候,由于对象被Static 关键字所修饰,会随着类的加载而加载,当我们...
  • ㊣java编程核心第2版多线程的图书75.5元包邮(需用券)去购买 >前言:在本文中会使用代码进行展示懒汉单例模式为什么需要进行二次判...代码:1、懒汉式单例模式:public class Singleton {// 使用volatile禁止指令...
  • /** 单例模式:* 饿汉式:类一加载就创建对象* 懒汉式:用的时候,才去创建对象* 面试题:单例模式的思想是什么?写一个代码体现(我们最好写懒汉式的单例模式给面/** 单例模式:* 饿汉式:类一加载就创建对象* 懒汉式:用...
  • 懒汉式单例演进到DCL懒汉式 深度全面解析本篇文章背景预期第一阶段:普通的懒汉式单例第二阶段:加锁懒汉式单例第三阶段:普通DCL懒汉式单例第四阶段:终极版DCL懒汉式单例小结 本篇文章背景 网上很多懒汉式单例模式...
  • 单例模式分为懒汉式和饿汉式, 不知道是谁命名的, 其实也比较形象 懒汉式,比较“懒”,只有用到的时候才去new对象。 饿汉式,比较“饿”,类加载的时候,就new对象,这应该算是勤快吧,笨鸟先飞的感觉。 饿汉式-...
  • 单例模式(饥汉式、懒汉式

    千次阅读 多人点赞 2021-01-18 20:01:49
    文章目录一、简单的单例模式要点二、实现步骤(详细)1、创建一个简单的构造函数2、构造函数私有化小结3、通过一个公有的方法提供访问小结4、创建一个成员变量小结5、简单单例函数优化(赖汉)6、简单单例函数(饥...
  • /**懒汉式比较懒,只有当调用getInstance的时候,才回去初始化这个单例 * @author dym * @date 2020/12/20 16:07 */ public class Lazy { private Lazy(){}; private static Lazy lazy = null; .
  • 单例模式思路分析饿汉式代码实现懒汉式 思路分析 在书写单例模式之前,我们需要先理解为什么需要单例模式 保证整个系统中一个类只有一个对象的实例,实现这种功能的方式就叫单例模式。 意图: 保证一个类仅有一...
  • //饿汉 public class Singleton1 { public static void main(String[] args) { MySingle single1 = MySingle.getSingle(); MySingle single2 = MySingle.getSingle(); System.out.println(single1 == single2...
  • 优缺点说明1)双重检查概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (singleton == null) 检查,这样就可以保证线程安全了2)这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == ...
  • //返回对象 } } 懒汉式的特点:方法被加载时才进行初始化操作,“懒汉式”又被称为延迟加载设计模式。 仔细观察,懒汉式的代码是有弊端的,我们来看看。 当多线程访问懒汉式时,因为懒汉式的方法内对共性数据进行多...
  • * 使用同步机制将单例模式中的懒汉式改写为线程安全的 * * @author shkstart * @create 2019-02-15 下午 2:50 */ public class BankTest { } class Bank{ private Bank(){} private static Bank instance...
  • 懒汉式: 在第一次调用时才会创建实例化对象,只适用于单线程模式。当在多线程中,如果多个线程同时进行,就会实例化多个对象。 懒汉式创建模式: //懒汉式 public class Person { public static Person p; ...
  • 所以当此 Singleton 类加载时,SingletonHolder 并不会被立即加载,所以不会像饿汉那样占用内存。 另外,Java 虚拟机规定,当访问一个类的静态字段时,如果该类尚未初始化,则立即初始化此类。当调用Singleton 的 ...
  • 懒汉式单例

    2021-11-05 09:51:18
    懒汉式单例 双重检测 //懒汉式单例 public class Singleton { private static Singleton singleton=null; //避免外区去new private Singleton() { } public static Singleton getSingleton() { if(singleton...
  • 2、实现方式: 饿汉式就是直接构造器中创建好了实例,而懒汉式就是调用方法的时候才会创建实例 2.1饿汉式 public final class SingletonTest1 { public static void main(String[] args) { Bank bank1 = Bank....
  • java单例模式:饿汉式、懒汉式

    千次阅读 2021-03-27 14:52:35
    单例模式分为饿汉式和懒汉式。 1. 饿汉式 直接创建对象,不存在线程安全问题。 静态常量方式 优点:这种写法比较简单,就是在类加载的时候就完成实例化。避免了线程同步问题。 缺点:在类加载的时候就完成实例...
  • java的懒汉式

    2021-03-15 01:48:41
    这样简单 ######嗯 饿汉式单例和带有同步机制的懒汉式单例都应该没问题######如果初始化开销大,这种方式就不太好。但是一般的,这种方式比较好。我也喜欢这种方式。###### 对的 可以参考《Java concurrency in ...
  • 简单的单例模式:(懒汉式)package com.zcp.juc.single;/*** @author zcp* @description* @created by 2020-03-26 22:50*/public final class Singleton {private static Singleton INSTANCE=null;private Singleton...
  • if(instance==null){ instance=new Bank(); } return instance; 未设置同步锁时会出现线程安全问题,在一个线程进入if语句后还未创建完成时,另一个线程也会进入if语句,导致Bank对象创建多次 ...
  • 单例模式:简单的来说,就是为了防止你在程序中new 来new去,明明只需要一个...首先我们看的是懒汉式,看这个名字就知道,它比较懒,注意他并没有直接创建对象,而是private static Lazy lazy=null;这是一个和饿汉式...
  • } } 当类被加载时,静态变量instantce会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建 四、懒汉式 public class LazySingleton { // 静态私有成员变量 private volatile static ...
  • 懒汉模式是在使用时才会创建(调用获取对象实例的时候才创建) 饿汉模式存在资源浪费的可能 饿汉模式不存在线程安全问题,懒汉模式存在线程安全问题 两种实现方式如下: package test; public class patterntest { ...
  • 先来看常见的使用锁解决懒汉式单例线程安全问题的例子 /** * @author ZJX * @date 2021/10/8 * @description */ public class LazySingleton { public static User user; public static User superUser(){ if...
  • 1. 饿汉 /** * @author :fan * @description: 饿汉 * @date :2020/10/1 12:16 */ public class Singleton { //让构造函数为 private,这样该类就不会被实例化 private Singleton() { } //创建不可变...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,200
精华内容 20,080
关键字:

懒汉式