02_单例模式

Posted africancu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02_单例模式相关的知识,希望对你有一定的参考价值。

一、单例模式
    单例模式(Singleton Pattern) 是一个比较简单的模式,其定义如下:
    Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例)
    单例模式通过定义一个私有访问权限的构造函数来避免被其他类new出来一个对象,然后该类自己创建一个实例,通过一个静态方法对外提供这个实例对象。
单例模式的通用代码如下:
代码清单1
public class Singleton {
    private static final Singleton singleton = new Singleton();
    private Singleton(){}

    public static Singleton getSingleton(){
        return singleton;
    } 
}

 

 
单例模式的注意事项
    首先,在高并发情况下,请注意单例模式的线程同步问题。单例模式有几种不同的实现方法,上面的例子不会出现产生多个实例的情况,但是下面的代码就有可能出现多个实例。
代码清单2:
public class Singleton {
    private static final Singleton singleton = null;
    private Singleton(){}

    public static Singleton getSingleton(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}
 
    该单例模式在低并发的情况下应该不会出现问题。若系统压力增大,并发量增加时则可能在内存中出现多个实例。为什么会出现这种情况呢?
    如果一个线程A执行到singleton = new Singleton(),但是还没有获得对象(对象初始化是需要时间的),第二个线程B也在执行,执行到if(singleton == null),那么线程B获得判断条件也是为真,于是继续执行下去,线程A获取了一个对象,线程B也获得了一个对象,在内存中就会出现两个对象。
 
    解决线程不安全的方法很多,可以在getSingleton方发前加synchronized关键字,也可以在getSingleton方法内加synchronized来实现,但都不是优秀的单例模式,建议读者使用如代码清单1的方式来实现单例模式。
 
    代码清单1的单例称为饿汉式单例
    增加了synchronized关键字的代码清单2单例称为懒汉式单例
 
二、单例模式的扩展
    如果一个类要求可以产生多个对象,直接new就可以了。如果一个类要求只能有一个对象,那么就使用单例模式。
    但是如果要求一个类只能产生两三个对象呢?该怎么实现?
//皇帝类
import java.util.ArrayList;
import java.util.Random;

public class Emperor {
    private static int maxNumOfEmperor = 2;
    private static ArrayList<String> nameList = new ArrayList<>();
    private static ArrayList<Emperor> emperorList = new ArrayList<>();
    private static int countNumOfEmperor = 0;

    static {
        for(int i = 0; i < maxNumOfEmperor; i++){
            emperorList.add(new Emperor("皇帝"+i));
        }
    }

    private Emperor(){}
    private Emperor(String name){
        nameList.add(name);
    }

    public static Emperor getInstance(){
        Random random = new Random();
        countNumOfEmperor = random.nextInt(maxNumOfEmperor);
        return emperorList.get(countNumOfEmperor);
    }
}


//大臣类
public class Minister {
    public static void main(String[] args) {
        for(int day = 0; day < 10; day++){
            Emperor emperor = Emperor.getInstance();
            System.out.println(emperor);
        }
    }
}

打印结果:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
 
从对象地址可以看到只产生了两个对象
 
这种需要产生固定数量对象的模式叫做有上限的多例模式,它是单例模式的一种扩展。
 

以上是关于02_单例模式的主要内容,如果未能解决你的问题,请参考以下文章

7.02_单例模式(懒汉模式,恶汉模式)

单例模式与多线程

设计模式之单例模式

Python面向对象之单例模式

单例设计模式代码实现

Java_static关键字,单例设计模式,代码块,final关键字,接口,内部类