单例模式的多种实现

package net.csdn.se.singletondemo;

/**
 * 线程安全的---懒汉式(懒加载)创建
 */
public class Singleton06 {

    //1\
    private Singleton06(){}

    /**
     * 2静态的内部类的方式来创建实例
     * 在内部类被加载和初始化时,才创建实例。
     * 静态内部类不会随着外部类的加载和初始化而初始化,而是在需要的时候才会进行加载和初始化
     */

    private static class Inner{
       private static Singleton06 INSTANCE = new Singleton06();
    }

    //3
    public static Singleton06 getInstance(){
        return Inner.INSTANCE;
    }

    public static void main(String[] args) {
        Singleton06 instance = Singleton06.getInstance();
        Singleton06 instance1 = Singleton06.getInstance();
        System.out.println(instance == instance1);//结果一直为True
    }


}

  1. 饿汉式创建三种方式
    package net.csdn.se.singletondemo;
    
    /**
     * 饿汉式直接创建单例
     * 1、只能创建一个实例 ---> 构造方法私有化
     * 2、创建出来的实例进行保存
     * 3、对外暴露
     * 总结:
     *      1、优点:基于classloader机制来创建的单例,没有不加锁执行效率高、但是也避免了线程安全问题
     *      2、缺点:类加载时即初始化了实例,因此没有达到lazyloading(延迟加载)的效果对于那些创建出来没有被使用的也没有被回收的类来说,导致浪费内存空间
     */
    public class Singleton01 {
    
        //1. 第一步,构造方法私有化,只创建一个实例
        private Singleton01(){}
        //2. 第二步,对创建出来的实例进行保存
        private static Singleton01 INSTANCE = new Singleton01();
        //3、第三步 对外进行暴露
        public Singleton01 getInstance(){
            return INSTANCE;
        }
    
    
    }
    
    package net.csdn.se.singletondemo;
    
    /**
     * 饿汉式 枚举的方式创建单例
     * 特点:
     *    代码简单,实现容易
     */
    public enum Singleton02 {
        INSTANCE;
    }
    
    class Singleton02Test{
        public static void main(String[] args) {
            Singleton02 instance = Singleton02.INSTANCE;
        }
    }
    package net.csdn.se.singletondemo;
    
    import javax.sound.midi.Soundbank;
    import java.io.IOException;
    import java.util.Properties;
    
    /**
     * 饿汉式实例
     * 使用静态代码块的方式创建单例
     */
    public class Singleton03 {
    
        //2\ 第二要素 进行保存
        private static Singleton03 INSTANCE; //
        static {
            INSTANCE  = new Singleton03();   //类加载的时候 可以写业务逻辑 
            //加载配置文件
            Properties properties = new Properties();
            try {
                properties.load(Singleton03.class.getClassLoader().getResourceAsStream("jdbc.properties"));
                String username = properties.getProperty("userName");
                String password = properties.getProperty("password");
                System.out.println(username);
                System.out.println(password);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //1 第一要素 构造方法私有化
        private Singleton03(){}
    
        //3 对外暴露
        public static Singleton03 getInstance(){
            return  INSTANCE;
        }
    
    
        public static void main(String[] args) {
            Singleton03 instance = Singleton03.getInstance();
            Singleton03 instance2 = Singleton03.getInstance();
            System.out.println(instance == instance2);
        }
    
    }
    

     

     

     

  2. 懒汉式创建三种方式
    package net.csdn.se.singletondemo;
    
    import java.awt.*;
    
    /**
     * 线程不安全的方式创建单例---懒汉式
     * 线程安全的方式创建单例 添加synchronized----懒汉式
     * 优点:layloading,第一次调用的使用才初始化,避免了内存的浪费
     * 缺点:必须加锁才能保证是单例的,影响了效率
     */
    public class Singleton04 {
        private static Singleton04 INSTANCE;
        private Singleton04(){}
    
    //    public static  Singleton04 getInstance(){ 线程不安全创建方式
        public static synchronized Singleton04 getInstance(){  //线程安全创建方式
            if(INSTANCE == null){ //
                INSTANCE = new Singleton04();
            }
            return INSTANCE;
        }
    }
    
package net.csdn.se.singletondemo;

/**
 * 线程安全的---懒汉式(懒加载)创建
 * 静态内部类不能传递参数
 */
public class Singleton06 {

    //1\
    private Singleton06(){}

    /**
     * 2静态的内部类的方式来创建实例
     * 在内部类被加载和初始化时,才创建实例。
     * 静态内部类不会随着外部类的加载和初始化而初始化,而是在需要的时候才会进行加载和初始化
/**
     * 2静态的内部类的方式来创建实例
     静态内部类的优点是:外部类加载时并不需要立即加载内部类,
     内部类不被加载则不去初始化INSTANCE,故而不占内存。
     即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,
     才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,
     这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

     那么,静态内部类又是如何实现线程安全的呢?
     getInstance()方法,Inner.INSTANCE,取的是Inner里的INSTANCE对象,
     跟上面那个DCL方法不同的是,getInstance()方法并没有多次去new对象,
     故不管多少个线程去调用getInstance()方法,取的都是同一个INSTANCE对象,
     而不用去重新创建。当getInstance()方法被调用时,Inner才在Singleton06的运行时常量池里,
     把符号引用替换为直接引用,这时静态对象INSTANCE也真正被创建,然后再被getInstance()方法返回出去,
     这点同饿汉模式。那么INSTANCE在创建过程中又是如何保证线程安全的呢?在《深入理解JAVA虚拟机》中,有这么一句话:

     虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,但如果执行<clinit>()方法后,其他线程唤醒之后不会再次进入<clinit>()方法。同一个加载器下,一个类型只会初始化一次。),在实际应用中,这种阻塞往往是很隐蔽的。

     故而,可以看出INSTANCE在创建过程中是线程安全的,所以说静态内部类形式的单例可保证线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
       */
     */

    private static class Inner{
       private static Singleton06 INSTANCE = new Singleton06();
    }

    //3
    public static Singleton06 getInstance(){
        return Inner.INSTANCE;
    }

    public static void main(String[] args) {
        Singleton06 instance = Singleton06.getInstance();
        Singleton06 instance1 = Singleton06.getInstance();
        System.out.println(instance == instance1);//结果一直为True
    }


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值