千家信息网

如何实现Singleton模式

发表于:2024-10-23 作者:千家信息网编辑
千家信息网最后更新 2024年10月23日,如何实现Singleton模式,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。题目设计一个类,我们只能生成该类的一个实例分
千家信息网最后更新 2024年10月23日如何实现Singleton模式

如何实现Singleton模式,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

题目

设计一个类,我们只能生成该类的一个实例

分析

最简单实现

  • 私有构造方法

  • 静态方法获取实例

是否需要考虑内存或并发环境

如果需要考虑内存,使用到时才创建实例对象(饿汉),不使用时就不创建实例(懒汉,懒加载)。

如果需要考虑线程安全,就要确保获取实例是同步的,避免创建多个实例。

实现方式

  • [x] 1. 单线程(懒汉式、饿汉式)

  • [x] 2. 多线程工作效率不高(加锁获取实例的方法)

  • [x] 3. 加同步锁前后两次判断实例是否已存在

  • [x] 4. 利用静态初始化创建实例(推荐,线程安全,会占用一部分内存)

  • [x] 5. 利用静态内部类实现按需创建实例(最推荐,线程安全,效率高,聪明的你应该可以明白的)

编码实现

1. 单线程(懒汉式、饿汉式)

饿汉单例
package cn.jast.java.offer.singleton;/** * 简单饿汉单例 * */public class SimpleHungerSingleton {    private static SimpleHungerSingleton simpleSingleton;    private SimpleHungerSingleton(){        simpleSingleton = new SimpleHungerSingleton();    }    public static SimpleHungerSingleton getInstance(){        return simpleSingleton;    }}
简单懒汉单例
package cn.jast.java.offer.singleton;/** * 简单懒汉单例 *  */public class SimpleLazySingleton {    private static SimpleLazySingleton simpleSingleton;    private SimpleLazySingleton(){    }    public static SimpleLazySingleton getInstance(){        if(simpleSingleton == null){            simpleSingleton = new SimpleLazySingleton();        }        return simpleSingleton;    }}
线程安全测试
/**     * 测试简单单例的线程安全     */    public static void testSimpleLazySingleton(){        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                SimpleLazySingleton simpleLazySingleton = SimpleLazySingleton.getInstance();                singletonSet.add(simpleLazySingleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }

输出:

简单单例存在创建多个实例对象,实例如下:[cn.jast.java.offer.singleton.SimpleLazySingleton@2b9283d, cn.jast.java.offer.singleton.SimpleLazySingleton@72fba635]

2. 多线程工作效率不高(加锁获取实例的方法)

package cn.jast.java.offer.singleton;public class Synchronized1Singleton {    private static Synchronized1Singleton instance;    private Synchronized1Singleton(){    }    /**     * 每次获取对象时都加锁来确保创建对象     * @return     */    public static synchronized Synchronized1Singleton getInstance(){        if(instance == null){            instance = new Synchronized1Singleton();        }        return instance;    }}

测试:

public static void testSynchronized1Singleton(){        long startTime = System.currentTimeMillis();        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                Synchronized1Singleton singleton = Synchronized1Singleton.getInstance();                singletonSet.add(singleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                System.out.println(String.format("执行时间:%s ms",System.currentTimeMillis()-startTime));                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }

输出:

执行时间:72 ms(注:一个样例)

3. 加同步锁前后两次判断实例是否已存在

package cn.jast.java.offer.singleton;public class Synchronized2Singleton {    private static Synchronized2Singleton instance;    private Synchronized2Singleton(){    }    public static Synchronized2Singleton getInstance(){        if(instance == null){            synchronized (Synchronized2Singleton.class){                if(instance==null){                    instance = new Synchronized2Singleton();                }            }        }        return instance;    }}

4. 利用静态初始化创建实例(推荐,线程安全

package cn.jast.java.offer.singleton;/** * 推荐 */public class StaticInitializeSingleton {    private static StaticInitializeSingleton instance ;    static{        instance = new StaticInitializeSingleton();    }    private StaticInitializeSingleton(){    }    public static StaticInitializeSingleton getInstance(){        return instance;    }}

5. 利用静态内部类实现按需创建实例(最推荐,线程安全,效率高

package cn.jast.java.offer.singleton;/** * 推荐 */public class StaticInnerClassSingleton {    private StaticInnerClassSingleton(){    }    public static StaticInnerClassSingleton getInstance(){        return Inner.instance;    }    private static class Inner{        private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();    }}

完整的测试

package cn.jast.java.offer.singleton;import java.util.*;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Main {    public static void main(String[] args) {//        testSimpleLazySingleton();        testSynchronized1Singleton();//        testSynchronized2Singleton();//        testStaticInitializeSingleton();//        testNestedClassSingleton();    }    /**     * 测试简单单例的线程安全     */    public static void testSimpleLazySingleton(){        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                SimpleLazySingleton simpleLazySingleton = SimpleLazySingleton.getInstance();                singletonSet.add(simpleLazySingleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }    /**     * 测试线程安全的单例模式实现     */    public static void testSynchronized1Singleton(){        long startTime = System.currentTimeMillis();        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                Synchronized1Singleton singleton = Synchronized1Singleton.getInstance();                singletonSet.add(singleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                System.out.println(String.format("执行时间:%s ms",System.currentTimeMillis()-startTime));                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }    /**     * Synchronized2Singleton 的效率比 Synchronized1Singleton高几倍甚至几十倍以上     */    public static void testSynchronized2Singleton(){        long startTime = System.currentTimeMillis();        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                Synchronized2Singleton singleton = Synchronized2Singleton.getInstance();                singletonSet.add(singleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                System.out.println(String.format("执行时间:%s ms",System.currentTimeMillis()-startTime));                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }    /**     *     */    public static void testStaticInitializeSingleton(){        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                Synchronized2Singleton singleton = Synchronized2Singleton.getInstance();                singletonSet.add(singleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }    public static void testNestedClassSingleton(){        Set singletonSet = Collections.synchronizedSet(new HashSet<>());        ExecutorService executorService = Executors.newFixedThreadPool(50);        for (int i = 0; i < 10; i++) {            executorService.submit(()->{                StaticInnerClassSingleton singleton = StaticInnerClassSingleton.getInstance();                singletonSet.add(singleton);            });        }        executorService.shutdown();        while(true){            if(executorService.isShutdown()){                if(singletonSet.size()>1){                    System.out.println("简单单例存在创建多个实例对象,实例如下:");                    System.out.println(singletonSet);                }                break;            }        }    }}

自问自答

问:单例模式获取实例的方法为什么是静态方法? 答:因为构造方法是私有的,无法通过new创建实例,那只能通过类方法获取实例。那通过反射是否可以创建实例呢?

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。

0