美文网首页
java 单例模式

java 单例模式

作者: 梦之马 | 来源:发表于2019-08-15 21:01 被阅读0次

    写在前面:这篇文章主要不同之处在于提供了,
    1、多线程测试,用于检查对象是否是单例
    2、加入了我自己的理解

    单例模式是创建型模式的一种,主要用户创建唯一的对象。
    应用场景,比如数据库链接,window 任务控制器,日历对象等

    懒加载模式

    对象在使用的时候才进行加载,不使用不加载节省内存空间的作用

    关键字 synchronized 的原子性使同一时刻仅有一个线程在执行,那么第一个获得锁的线程,进入 p1、p2 会进行实例化,第一个获得锁的线程释放锁之后,后面进入的线程 在 p1 处 false 则不会进行实例化。
    从而保证了对象的单例性

    public class Singleton {
        private static Singleton instance = null;
    
        //不允许实例化
        private Singleton() {
            try {
                //模拟耗时创建,比如链接建立等
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static synchronized Singleton getInstance() {
            if (instance == null) { // p1
                instance = new Singleton();  // p2
            }
        }
    

    从上面可以看出,在方法上加锁 synchronized ,会让每个次获取单例对象的时候,频繁地取锁和释放锁,会造成较大的开销(我也没试过,你们可以试试)

    作为优化,我们需要缩小锁的范围,获取已创建的对象时,不用加锁,仅在创建对象的时候加锁。
    所以双重检查的单例模式,第一重检查的是对象是否已创建,第二重检查多线程模式下是否已有线程创建对象

    ps:加有我注释的代码可以删除

    package com.github.songjiang951130.designpattern.singleton;
    
    public class Singleton {
        private static Singleton instance = null;
    
        //不允许实例化
        private Singleton() {
            try {
                //模拟耗时创建,比如链接建立等
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static Singleton getInstance() {
            //第一重检查 检查对象是否创建成功,
            //1、没有则由线程去创建
            //2、有则不进入代码同步块中加快获取对象速度
            if (instance == null) {
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " synchronized status:" + (instance == null));
                /**
                 * 当创建单例对象时间较长时(故意将构造函数sleep),会有多个线程在此处 等待获取锁 进入同步块(如下日志),同一时间仅有一个线程进入
                 * id name
                 * 26 Thread-14 synchronized status:true
                 * 33 Thread-21 synchronized status:true
                 * 35 Thread-23 synchronized status:true
                 * 38 Thread-26 synchronized status:true
                 * 39 Thread-27 synchronized status:true
                 * 36 Thread-24 synchronized status:true
                 * 31 Thread-19 synchronized status:false
                 * 37 Thread-25 synchronized status:false
                 * 32 Thread-20 synchronized status:false
                 * 30 Thread-18 synchronized status:false
                 */
                synchronized (Singleton.class) {
                    System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " start status:" + (instance == null));
                    //第二重检查,此处会有多个线程来创建,用于避免多个线程创建对象,破坏了单例模式
                    if (instance == null) {
                        System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " create");
                        instance = new Singleton();
                        //此处对象创建完成后即可新进入第一重检查的获取
                    }
                    System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " end  status:" + (instance == null));
                }
            }
            return instance;
        }
    }
    
        private static Singleton instance = null;
       // 此处有加volatile 使对象可见,测试了后没发现什么好处,暂时没加。主要是没做性能测试,懒得写了
        private static volatile Singleton instance = null;
    

    测试用例:多线程测试

    package com.github.songjiang951130.designpattern.singleton;
    
    import org.junit.Assert;
    import org.junit.Test;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    
    public class SingletonTest {
        List<Singleton> list;
    
        @Test
        public void test() {
            int threadCount = 100;
            list = new ArrayList<Singleton>(threadCount);
            CountDownLatch countDownLatch = new CountDownLatch(threadCount);
            for (int i = 0; i < threadCount; i++) {
                new Thread(new work(countDownLatch)).start();
            }
    
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //测试每个对象是否相等,第一次仅赋值
            Singleton singleton = null;
            for (Singleton element : list) {
                if (singleton == null) {
                    singleton = element;
                    continue;
                }
                Assert.assertEquals(singleton, element);
                singleton = element;
                System.out.println(element);
            }
            list = null;
        }
    
        public class work implements Runnable {
            CountDownLatch countDownLatch;
    
            public work(CountDownLatch countDownLatch) {
                this.countDownLatch = countDownLatch;
            }
    
            @Override
            public void run() {
                Singleton singleton = Singleton.getInstance();
                list.add(singleton);
                countDownLatch.countDown();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:java 单例模式

          本文链接:https://www.haomeiwen.com/subject/ofmtsctx.html