【设计模式】JAVA单例模式实战、学习

大家好,我是walker
一个从文科自学转行的程序员~
爱好编程,偶尔写写编程文章和生活
欢迎关注公众号【I am Walker】,回复“电子书”,就可以获得200多本编程相关电子书哈~
我的gitee:https://gitee.com/shen-chuhao/walker.git 里面很多技术案例!

单例模式

  • 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。
  • 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。

懒汉式

懒汉式:默认不会实例化,什么时候用什么时候new。

代码实例
package com.walker.test.designMode.signleton;

public class LazySingleton {
    
    //static 修饰
    private static LazySingleton instance;
    
    //私有构造函数
    private LazySingleton(){}
    
    //static synchronized
    public static synchronized LazySingleton getInstance(){
        //如果实例为null则创建
        if(instance==null){
            instance=new LazySingleton();
        }
        return instance;
    }
}

测试结果
package singletonPattern.lazy;

public class LazyTest {
    public static void main(String[] args) {
        LazySingleton instance = LazySingleton.getInstance();
        System.out.println(instance);
        LazySingleton instance2 = LazySingleton.getInstance();
        System.out.println(instance2);

        ThreadTest threadTest = new ThreadTest();
        threadTest.start();

        /**
        * 输出结果:线程不安全
         * singletonPattern.lazy.LazySingleton@677327b6
         * singletonPattern.lazy.LazySingleton@14ae5a5
         * singletonPattern.lazy.LazySingleton@32c3e0c4
        */

    }
}

饿汉式

饿汉式:类加载的时候就实例化,并且创建单例对象。

代码实例
package com.walker.test.designMode.signleton;
/**
* 饿汉式 方式一
*/
public class HungrySingleton {
    
    
    //直接实例化
    private static HungrySingleton instance=new HungrySingleton();
    
    private HungrySingleton(){}
    
    //直接返回结果
    public static HungrySingleton getInstance(){
        return instance;
    }
}




package singletonPattern.hungry;
/**
* 饿汉式 方式二
*/
public class HungrySingleton2 {

    private HungrySingleton2(){}

    private static HungrySingleton2 instance=null;
    static {
        instance=new HungrySingleton2();
    }

    public static HungrySingleton2 getInstance(){
        return instance;
    }
}


测试结果
package singletonPattern.hungry;

public class HungryTest {

    public static void main(String[] args) {
        HungrySingleton1 instance = HungrySingleton1.getInstance();
        System.out.println(instance);
        HungrySingleton1 instance2 = HungrySingleton1.getInstance();
        System.out.println(instance2);

        /**
         * 执行结果: 相同,线程安全
        * singletonPattern.hungry.HungrySingleton@677327b6
         * singletonPattern.hungry.HungrySingleton@677327b6
        */
    }
}

双检锁/双重校验锁

  • 这个可以说是懒汉式的进化版,增加了volatile实现可见性,以及synchronized实现了线程安全。
代码实例
package com.walker.test.designMode.signleton;

public class DoubleLockSingleton {
    //volatile
    private static volatile DoubleLockSingleton instance=null;
    
    //构造方法不提供外部使用,因此是private
    private DoubleLockSingleton(){}
    
    
    private static DoubleLockSingleton getInstance(){
        //先判null
        if(instance==null){
            //对该类进行加锁
            synchronized (DoubleLockSingleton.class){
                //再判null,因为可能有些线程在加锁之后已经为非null,这个时候就直接返回即可
                if(instance==null){
                    instance=new DoubleLockSingleton();
                }
            }
        }
        return instance;
    }
}




测试结果
package singletonPattern.doubleCheck;

public class DoubleCheckLockTest {
    public static void main(String[] args) {
        DoubleCheckLock instance = DoubleCheckLock.getInstance();
        System.out.println(instance);
        DoubleCheckLock instance1 = DoubleCheckLock.getInstance();
        System.out.println(instance1);
        DoubleCheckLock instance2 = DoubleCheckLock.getInstance();
        System.out.println(instance2);


        /**
        * singletonPattern.doubleCheck.DoubleCheckLock@677327b6
         * singletonPattern.doubleCheck.DoubleCheckLock@677327b6
         * singletonPattern.doubleCheck.DoubleCheckLock@677327b
         *
         * 线程安全
        */
    }
}

ThreadLocal

ThreadLocal是一种容器,将对象进行拷贝,相当于以空间换时间

package singletonPattern.threadlocal;

public class Singleton {
    private Singleton(){}

    /**
    * 使用final和static
     * final代表这个变量引用不可以被修改
     * 空间替换时间
    */
    private static final ThreadLocal<Singleton> instance=new ThreadLocal<Singleton>(){
        @Override
        protected Singleton initialValue() {
            return new Singleton();
        }
    };

    public static Singleton getInstance(){
        return instance.get();
    }
}

测试
package singletonPattern.threadlocal;

public class Test {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance1);
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance2);


        /**
        * singletonPattern.threadlocal.Singleton@677327b6
         * singletonPattern.threadlocal.Singleton@677327b6
         * 返回结果一致,线程安全
        */

    }
}

枚举

package singletonPattern.enums;

/**
* 枚举类的成员变量其实都是静态类型的,并且是在
 *  * 静态代码块中实例化的,有点像饿汉模式,也是天然线程安全的
*/
public enum Singleton {
    INSTANCE;

    Singleton() {
    }
}

懒汉式和饿汉式区别: 4

  • 实例化方面:
    • 懒汉式默认不会实例化,外部什么时候调用什么时候new。
    • 饿汉式在类加载的时候就实例化,并且创建单例对象。
  • 线程安全方面:
    • 饿汉式线程安全 (在线程还没出现之前就已经实例化了,因此饿汉式线程一定是安全的)。
    • 懒汉式线程不安全( 因为懒汉式加载是在使用时才会去new 实例的,那么你去new的时候是一个动态的过程,是放到方法中实现的,比如:public static synchronized Lazy getInstance(){ if(lazy==null){ lazy=new Lazy(); } 如果这个时候有多个线程访问这个实例,这个时候实例还不存在,还在new,就会进入到方法中,有多少线程就会new出多少个实例。一个方法只能return一个实例,那最终return出哪个呢?是不是会覆盖很多new的实例?这种情况当然也可以解决,那就是加同步锁,避免这种情况发生) 。
  • 执行效率上:
    • 饿汉式没有加任何的锁,因此执行效率比较高。
    • 懒汉式一般使用都会加同步锁,效率比饿汉式差。
  • 性能上:
    • 饿汉式在类加载的时候就初始化,不管你是否使用,它都实例化了,所以会占据空间,浪费内存。
    • 懒汉式什么时候需要什么时候实例化,相对来说不浪费内存。

实战应用

  • 线程池
  • 创建jedis

参考文档:https://www.cnblogs.com/kuangdw/p/12840026.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WalkerShen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值