创建型模式.单例模式-懒汉、饿汉、枚举、原子

1 安全发布对象的四种方法

在多线程中,为了保证线程安全性,我们要正确地发布对象,保证发布地对象不要逸出。

  • 在静态初始化函数中初始化一个对象引用
  • 将对象的引用保存到volatile类型域或者AtomicReference对象中
  • 将对象的引用保存到某个正确构造对象的final类型域中
  • 将对象的引用保存到一个由锁保护的域中

2 懒汉单例模式

写法简单,适合简单、小的对象创建;

当创建一个非常复杂、非常大I/O操作、非常耗内存的对象时,不宜采用;

package com.dhm.singleton;

/**
 * 懒汉单例模式
 * @author duhongming
 * @email [email protected]
 */
public class LazySingletonPattern {

    //方法1 声明为常量
    private static final LazySingletonPattern instance = new LazySingletonPattern();

    //方法2 静态代码块
    /*private static LazySingletonPattern instance = null;
    static{
        instance = new LazySingletonPattern();
    }*/

    //构造方法私有
    private LazySingletonPattern(){}

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

3 饿汉单例模式(volatile+双重检测机制)

适合绝大多数情况;

编写复杂,由于加锁,对性能有一定影响;

package com.dhm.singleton;

/**
 * 饿汉单例模式(volatile+双重检测机制)
 * @author duhongming
 * @email [email protected]
 *
 * 创建对象过程:
 * 1、memory = allocate()分配对象的内存空间
 * 2、ctorInstance() 初始化对象
 * 3、instance = memory 设置instance指向刚分配的内存
 *
 * 2和3会发生指令重排
 *
 * volatile作用:内存可见+防止指令重排
 */
public class HungrySingletonPattern {

    /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
    private volatile static HungrySingletonPattern instance = null;

    /* 私有构造方法,防止被实例化 */
    private HungrySingletonPattern(){}

    /* 因为我们只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字 */
    private static synchronized void syncInit() {//同步锁,静态方法锁定作用域是对象
        if (instance == null) {
            instance = new HungrySingletonPattern();
        }
    }

    /* 静态的工厂方法,创建实例 */
    public static HungrySingletonPattern getInstance(){
        if(instance == null){//双重检测机制
            syncInit();
        }
        return instance;
    }

    /* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
    public Object readResolve(){
        return instance;
    }
}

4 枚举单例模式

终极解决方案,请使用!

package com.dhm.singleton;

/**
 * 枚举单例模式
 * @author duhongming
 * @email [email protected]
 */
public class EnumSingletonPattern {

    private EnumSingletonPattern(){}

    public static EnumSingletonPattern getInstance() {
        return Singleton.INSTANCE.getIntance();
    }

    private enum Singleton{

        INSTANCE;

        private EnumSingletonPattern instance;

        //JVM保证这个只执行一次
        Singleton(){
            instance = new EnumSingletonPattern();
        }

        public EnumSingletonPattern getIntance(){
            return instance;
        }
    }
}

5 原子布尔变量单例模式

呵呵,纯属娱乐!

package com.dhm.singleton;

import java.util.concurrent.atomic.AtomicBoolean;
/**
 * 原子布尔变量单例模式
 * @author duhongming
 * @email [email protected]
 */
public class AtomicBooleanSingletonPattern {

    private static final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    private AtomicBooleanSingletonPattern(){}

    private static AtomicBooleanSingletonPattern intance = null;

    public static AtomicBooleanSingletonPattern getInstance() {
        if(atomicBoolean.compareAndSet(false,true)){
            intance = new AtomicBooleanSingletonPattern();
        }
        return intance;
    }
}

6 单例模式在多线程下的测试

package com.dhm.singleton;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 四种单例模式测试
 * @author duhongming
 * @email [email protected]
 */
public class SingletonPatternTest{
    private static final HungrySingletonPattern hungrySingletonPattern = HungrySingletonPattern.getInstance();
    private static final LazySingletonPattern lazySingletonPattern = LazySingletonPattern.getInstance();
    private static final EnumSingletonPattern enumSingletonPattern = EnumSingletonPattern.getInstance();
    private static final AtomicBooleanSingletonPattern atomicBooleanSingletonPattern = AtomicBooleanSingletonPattern.getInstance();

    /**
     * 初始化原子操作AtomicBoolean为false,只要有一个为false,
     * 它就会置为true,只要不为true,我们单例模式都是可以正常运行的
     */
    private static final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    private static final int TEST_NUM = 1000000;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        CountDownLatch countDownLatch1 = new CountDownLatch(TEST_NUM);
        CountDownLatch countDownLatch2 = new CountDownLatch(TEST_NUM);
        CountDownLatch countDownLatch3 = new CountDownLatch(TEST_NUM);
        CountDownLatch countDownLatch4 = new CountDownLatch(TEST_NUM);

        Long start1 = System.currentTimeMillis();
        for (int i = 0; i < TEST_NUM; i++) {
            executorService.execute(()->{
                try{
                    doHungrySingletonPatternTest();
                } finally {
                    countDownLatch1.countDown();
                }
            });
        }
        countDownLatch1.await();
        System.out.println("doHungrySingletonPatternTest cost time:"+(System.currentTimeMillis()-start1));

        Long start2 = System.currentTimeMillis();
        for (int i = 0; i < TEST_NUM; i++) {
            executorService.execute(()->{
                try{
                    doLazySingletonPatternTest();
                } finally {
                    countDownLatch2.countDown();
                }
            });
        }
        countDownLatch2.await();
        System.out.println("doLazySingletonPatternTest cost time:"+(System.currentTimeMillis()-start2));

        Long start3 = System.currentTimeMillis();
        for (int i = 0; i < TEST_NUM; i++) {
            executorService.execute(()->{
                try{
                    doEnumSingletonPatternTest();
                } finally {
                    countDownLatch3.countDown();
                }
            });
        }
        countDownLatch3.await();
        System.out.println("doEnumSingletonPatternTest cost time:"+(System.currentTimeMillis()-start3));

        Long start4 = System.currentTimeMillis();
        for (int i = 0; i < TEST_NUM; i++) {
            executorService.execute(()->{
                try{
                    doAtomicBooleanSingletonPatternTest();
                } finally {
                    countDownLatch4.countDown();
                }
            });
        }
        countDownLatch4.await();
        System.out.println("doAtomicBooleanSingletonPatternTest cost time:"+(System.currentTimeMillis()-start4));

        executorService.shutdown();

        if(!atomicBoolean.get()){
            System.out.println("单例模式测试通过!");
        }else{
            System.out.println("单例模式测试失败...");
        }
    }

    private static void doHungrySingletonPatternTest(){
        Boolean isEquals = hungrySingletonPattern.hashCode()==HungrySingletonPattern.getInstance().hashCode();
        if(atomicBoolean.compareAndSet(isEquals,true)){
            System.out.println("doHungrySingletonPatternTest fail");
        }
    }
    private static void doLazySingletonPatternTest(){
        Boolean isEquals = lazySingletonPattern.hashCode()==LazySingletonPattern.getInstance().hashCode();
        if(atomicBoolean.compareAndSet(isEquals,true)){
            System.out.println("doLazySingletonPatternTest fail");
        }
    }
    private static void doEnumSingletonPatternTest(){
        Boolean isEquals = enumSingletonPattern.hashCode()==EnumSingletonPattern.getInstance().hashCode();
        if(atomicBoolean.compareAndSet(isEquals,true)){
            System.out.println("doEnumSingletonPatternTest fail");
        }
    }
    private static void doAtomicBooleanSingletonPatternTest(){
        Boolean isEquals = atomicBooleanSingletonPattern.hashCode()==AtomicBooleanSingletonPattern.getInstance().hashCode();
        if(atomicBoolean.compareAndSet(isEquals,true)){
            System.out.println("doAtomicBooleanSingletonPatternTest fail");
        }
    }
}

猜你喜欢

转载自my.oschina.net/duhongming52java/blog/1785989
今日推荐