设计模式 单例模式的几种实现方式

一 简介

单例模式,对于一个类只有一个实例化对象。

必要点:

 私有化 构造方法,不让new

 编写类方法 暴露单例对象

 私有化单例对象,只提供给内部使用

 

 

二 考虑到并发条件下的情况下

实现方式主要有如下四种

 第一种,饿汉模式随着类加载,而实例化。类只会实例化一次,所以不会有并发的问题

 

/**
 * @program: test
 * @description: 单例  四种实现方式  第一饿汉式  类加载就初始化
 *                第二  懒汉式  方法加锁
 *                第三 双重效验
 *                第四 静态内部类
 * @author:
 * @create: 2019-07-09 19:46
 */
public class Singleton {
    private Singleton() {

    }

    private static Singleton singleton = new Singleton();

    public static Singleton getSingleton() {
        return singleton;
    }

}

  

第二种 对方法封锁,保证临界资源安全,好处:想加载时,才加载

public class Singleton1 {
    private static Singleton1 singleton1;
    private Singleton1() {

    }

    public synchronized static Singleton1 getSingleton() {
        if(singleton1==null)
            singleton1 = new Singleton1();  //只有第一次进入方法体的时候 创建对象
        return singleton1;
    }

}

  对比的是一种,线程不安全的。

/**
 * @program: test
 * @description: 不加限制的懒加载
 * @author:
 * @create: 2019-07-09 20:09
 */
public class Singleton4 {
    private static Singleton4 singleton4;

    private Singleton4() {

    }



    public static Singleton4 getSingleton() {
        if (singleton4 == null) {
            singleton4 = new Singleton4();
        }
        return singleton4;

    }
}

  第三种 方法:双检验

public class Singleton3 {

    private static volatile Singleton3 singleton3;

    private Singleton3() {

    }

    public static Singleton3 getSingleton() {
        if (singleton3 == null) {
            synchronized (Singleton3.class) {
                if (singleton3 == null) {
                    singleton3 = new Singleton3();
                }
            }       //同样 保证第一次 进入方法体 进行初始化   优化第二种情况
        }
        return singleton3;
    }

}

  第四种方法:利用内部类的特性,内部类可以访问外部类的变量;内部类同样也只会加载一次

public class Singleton2 {
    private static Singleton2 singleton2;

    private Singleton2() {

    }

    private static class SingletonPv {
        private static Singleton2 singleton2 = new Singleton2();
    }

    private Singleton2 getSingleton() {
        return SingletonPv.singleton2;
    }
}

  

最后是测试,让100个线程 同时去获取单例对象,四种方法 都没问题;而没加并发限制,很容易出现100个线程获得的对象不相同的情况

public class Main {
    public static void main(String[] args) {
        final CountDownLatch countDownLatch = new CountDownLatch(100);
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        countDownLatch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println( Singleton3.getSingleton()+Thread.currentThread().getName());
                }
            });
            thread.start();
            countDownLatch.countDown();

        }
    }
}

  

 

posted @ 2019-07-09 22:25  菜鸡wdq  阅读(425)  评论(0编辑  收藏  举报