什么是单例模式?
定义:Ensure a classes has only one instance, and provide a global point of access to it.确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
为什么要用单例模式?
- 由于单例模式在内存中只有一个实例,当对一个对象频繁创建和销毁时作用明显
- 减少系统的性能开销。当一个对象产生需要大量的资源时,例如读取配置等,可以在应用层启动时即产生一个单例
- 避免资源多重占用,例如同时写问题
- 设置全局的访问点
怎么使用单例模式?
饿汉式
public class HungrySingle {
private HungrySingle(){}
private static final HungrySingle hungrySingle = new HungrySingle();
public static HungrySingle getInstance(){
return hungrySingle;
}
}
在什么时候使用?
- 要求使用唯一序列号
- 共享访问点,共享数据
- 对象消耗资源过多
- …
怎么解决线程不安全问题?
双重加锁
public class DoubleSafeSingle {
private DoubleSafeSingle(){}
//volatile防止重排序
private static volatile DoubleSafeSingle single = null;
//双重检查
public static DoubleSafeSingle getInstance(){
if (single == null){
synchronized (DoubleSafeSingle.class){
if (single == null)
single = new DoubleSafeSingle();
}
}
return single;
}
}
单例模式出现性能问题,怎么解决?
由于单例模式只有一个对象,在读取资源时可能会降低性能,这时可以生产有限个单例模式来解决。
/**
* 有上限的多例模式,修正单例可能存在的性能问题
*/
public class MultiSingleDemo {
public static void main(String[] args) {
int len = 10;
for (int i = 0; i < len; i++){
MultiSingle multiSingle = MultiSingle.getInstance();
MultiSingle.say();
}
}
}
class MultiSingle{
// 定义最多能产生的实例变量
private static int maxNumOfSingle = 2;
// 使用ArrayList来容纳单例私有属性
private static ArrayList<String> nameList = new ArrayList<>();
// 定义一个列表,容纳所有单例
private static ArrayList<MultiSingle> multiSingleList = new ArrayList<>();
// 当前单例序列号
private static int countNumOfMultiSingle = 0;
static {
for (int i = 0; i < maxNumOfSingle; i++){
multiSingleList.add(new MultiSingle("单例" + (i + 1)));
}
}
private MultiSingle(){
}
private MultiSingle(String name){
nameList.add(name);
}
/**
* 随机生成单例
* @return
*/
public static MultiSingle getInstance(){
Random random = new Random();
countNumOfMultiSingle = random.nextInt(maxNumOfSingle);
return multiSingleList.get(countNumOfMultiSingle);
}
public static void say(){
System.out.println(nameList.get(countNumOfMultiSingle));
}
}