java-设计模式-单例-有限多例

java单例的实现有多种,这里介绍简单的几种:

单例都是要求 构造方法私有化

1:内部类模式(推荐使用)

特点:能实现懒加载、是线程安全的,不用锁实现

/**
 * 内部类实现单例
 * 0:只初始化一个
 * 1:懒加载
 * 2:线程安全
 */
public class InnerSingle{
    private InnerSingle(){
        System.out.println("内部类初始化");
    }
    public static InnerSingle getInstance(){
        return InnerHelper.innerSingle;
    }
    private static class InnerHelper{
        private static InnerSingle innerSingle = new InnerSingle();

    }
}

2:饿汉模式 - 怕挨饿,先实例

特点:静态属性中新建对象

优点:线程安全、性能也高      缺点:不能懒加载

/**
 * 单例 - 饿汉
 */
public class SingleHungry {
    private static SingleHungry singleHungry = new SingleHungry();
    private SingleHungry(){
        System.out.println("初始化");
    }
    public static SingleHungry getInstance(){
        return singleHungry;
    }
}

3:懒汉模式 - 用到再实例

普通模式:不用同步关键字,为线程不安全 

    if(instance == null){

        instance = new Single()
    }

方法锁模式:在getInstance方法前加入 同步 关键字得意实现线程安全。

扫描二维码关注公众号,回复: 10063460 查看本文章

特点:在初始化完成后,每次调用都需要去竞争锁,效率特别慢。

有点:解决了线程安全的问题。

public static synchronized getInstance() {
    if(instance == null){
        instance = new Single()
    }
}

双检查模式(重点学习)

加入volatile保证变量在不同线程间的 可见性

判断有无实例(第一次检查),只有在没有实例前才需要去走同步代码

获取锁后,还需要再次判断是否已经实例化了。(第二次检查,读者先思考下这里为什么要第二次检查,后面有限多例模式有解答)

public class SyncSingle {

    /**
     * 对保存实例的变量添加volatile的修饰
     */
    private volatile static SyncSingle instance = null;
    private SyncSingle(){
    }

    public static SyncSingle getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
        if(instance == null){
            //同步块,线程安全的创建实例
            synchronized(SyncSingle.class){
                //再次检查实例是否存在,如果不存在才真的创建实例
                if(instance == null){
                    instance = new SyncSingle();
                }
            }
        }
        return instance;

    }
}

有限多例模式

有限多例的意思是最多能实例化多少个,仿照单例模式的 懒汉的双检查 方法 来实现。


/**
 * 有限的多例 3个
 */
public class ThreeSingle {
    private ThreeSingle(){

    }
    private  static volatile   List<ThreeSingle> list = new ArrayList<>();
    private static  final int INSTANCE_MAX = 3;

    public static ThreeSingle getInstance(){
        if(list.size() < INSTANCE_MAX){
            synchronized (ThreeSingle.class){
                System.out.println("list size为"+list.size());
                if(list.size() < INSTANCE_MAX){//注意这点,需要重新检查,因为可能有多个线程(超过3个)等待锁,但是只有前3个线程能建立对象
                    ThreeSingle threeSingle = new ThreeSingle();
                    list.add(threeSingle);
                    System.out.println("add");
                }
            }
        }
//        System.out.println(list.size());
        return list.get(new Random().nextInt(list.size()));
    }

}

测试方法

 public static void main(String[] args) {
        for (int i =0;i<100;i++){
            new Thread(()->{
                ThreeSingle.getInstance();
            }).start();
        }
    }

得到的结果为:

list size为0
add
list size为1
add
list size为2
add
list size为3
list size为3
list size为3
list size为3
list size为3

结果中有多个 list size为3 ,说明在有超过3个线程在等待锁,获取锁之后,可能 list 已经超过3个了,所以这里需要再次检查。这就是为什么需要双检查的原因

如果你的多线程的知识储备不够,建议可以看看笔者的另外一篇博文:https://blog.csdn.net/xiaoluo5238/article/details/104380207

发布了60 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/xiaoluo5238/article/details/104560129
今日推荐