Singleton 单例模式(饿汉式,懒汉式,双重锁式和内部类式),多种实现方式

单例模式原理
通过私有化构造函数,通过静态公共方法/枚举方式返回对象。
注意:确保实例只有一个,尤其是多线程环境。

饿汉式

/**
 * 饿汉式(早new对象准备好,担心饿死)
 * @author:eddyjoe
 * @date:2019/3/7
 */
public class HungrySingle {
    /**为严谨,加final指向的引用不能再做修改*/
    private static final HungrySingle hungrySingle = new HungrySingle();

    private HungrySingle(){
    }

    public static HungrySingle getHungrySingle(){
        return hungrySingle;
    }
}

懒汉式

/**
 * 懒汉式(因为懒,需要时再new),线程不安全
 * @author:eddyjoe
 * @date:2019/3/7
 */
public class LazySingle {
    private static LazySingle lazySingle;

    private LazySingle(){
    }

    public static LazySingle getLazySingle(){
        if(null == lazySingle){
            lazySingle = new LazySingle();
        }
        return lazySingle;
    }
}

双重锁式

/**
 * 双重锁式【推荐】,针对懒汉式优化了线程安全
 * 将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,
 * 只有第一次才加锁同步,创建了以后就不用了。
 * @author:eddyjoe
 * @date:2019/3/7
 */
public class DoubleLockSingle {
    /**也可以加上volatile,各个线程之间使之内存可见,禁止指令重排,造成的bug
     * 多线程主要围绕可见性和原子性两个特性而展开,使用volatile关键字修饰的变量,保证了其在多线程之间的可见性*/
//    private static volatile DoubleLockSingle doubleLockSingle;
    private static  DoubleLockSingle doubleLockSingle;

    private DoubleLockSingle(){
    }

    public static DoubleLockSingle getDoubleLockSingle(){
        if(null == doubleLockSingle){
            //一开始对象为空可能有多个线程同时进来,12345...等线程1创建对象后,后面的线程就进不来了
            //注意静态方法同步不能用this
            System.out.println(Thread.currentThread().getName()+":Ready to grab");
            synchronized (DoubleLockSingle.class){
                //线程23456在傻傻排队拿锁,拿到锁也没它什么事了
                System.out.println(Thread.currentThread().getName()+":Line up to take the lock");
                if(null == doubleLockSingle){
                    System.out.println(Thread.currentThread().getName()+":I Won");
                    //线程1在建对象,线程2在候着,等线程1执行完到线程2拿到锁,判断对象不为空这是也进不来了
                    doubleLockSingle = new DoubleLockSingle();
                }
            }
        }
        return doubleLockSingle;
    }
}

测一下

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author:eddyjoe
 * @date:2019/3/7
 */
public class Clint {
    public static void main(String[] args) {
        int count = 1500;//并发数
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
        ExecutorService executorService = Executors.newFixedThreadPool(count);
        long now = System.currentTimeMillis();
        for (int i = 0; i < count; i++)
        executorService.execute(new Clint().new Task(cyclicBarrier));

        executorService.shutdown();
        while (!executorService.isTerminated()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("All is finished!---------"+(end-now));
    }
    public class Task implements Runnable {
        private CyclicBarrier cyclicBarrier;

        public Task(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                // 等待所有任务准备就绪
                cyclicBarrier.await();
                // 测试内容
                DoubleLockSingle single = DoubleLockSingle.getDoubleLockSingle();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

只打印一行 I Won 说明实现了线程安全
在这里插入图片描述

内部类式

/**
 * 静态内部类式【推荐】
 * 通过类加载机制来保证只创建一个instance实例。和饿汉模式一样,不存在多线程并发的问题。
 * 只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载。
 * 可以同时保证延迟加载和线程安全。
 * @author:eddyjoe
 * @date:2019/3/7
 */
public class InternalClassSingle {
    private static class InternalClass{
        public static InternalClassSingle internalClassSingle = new InternalClassSingle();
    }

    private InternalClassSingle(){
    }

    public static InternalClassSingle getInstance(){
        return InternalClass.internalClassSingle;
    }
}

枚举式(这种方式不常用,略)

猜你喜欢

转载自blog.csdn.net/eddyjoe/article/details/88316095