单例模式(singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。
实例:
先看饿汉式
package com.sl.demo.singleton;
/**
* 饿汉式(饿了,所以一上来就吃)
* @author pengkun
*
*/
public class StarveSingleton {
//在内部new一个自己
private static StarveSingleton singleton=new StarveSingleton();
//私有化构造,不让别人new
private StarveSingleton() {
}
//提供一个返回对象的方法
public static StarveSingleton getInstance() {
return singleton;
}
}
安全性
饿汉式天生就是线程安全的,当是它也没有其他的延迟加载特性,为什么会说到线程安全呢?接下来看下其他单例
懒汉式:
package com.sl.demo.singleton;
/**
* 懒汉式(因为懒,所以你什么时候要就什么时候给你创建)
* @author pengkun
*
*/
public class LazySingleton {
//在内部new一个自己
private static LazySingleton singleton;
//私有化构造,不让别人new
private LazySingleton() {
}
//提供一个返回对象的方法
public static LazySingleton getInstance() {
//判断该对象是否存在
if(singleton==null) {
singleton= new LazySingleton();
}
return singleton;
}
}
安全性:
为什么称之为懒汉式呢,我个人理解是因为它懒,它要等你什么时候要的时候才给你创建对象,所以也有延迟加载的特性,但是懒汉式是线程不安全的。当多个线程时,一个线程要创建对象了,但是还没完成,而另一个线程也进了if条件的时候,判断它
是成立的,因为对象还没创建好。
那我们怎么解决呢?肯定一下就想到了给getInstance()方法加synchronized。这样就可以了吗?你想想那不是每次进来都要经过synchronized?那效率也太低了
解决办法:双重锁
package com.sl.demo.singleton;
/**
* 懒汉式(因为懒,所以你什么时候要就什么时候给你创建)
* @author pengkun
*
*/
public class LazySingleton2 {
//在内部new一个自己
private static LazySingleton2 singleton=null;
//私有化构造,不让别人new
private LazySingleton2() {
}
//提供一个返回对象的方法(为确保线程安全,双重锁)
public static LazySingleton2 getInstance() {
//判断该对象是否存在
if(singleton==null) {
synchronized (LazySingleton2.class) {
if(singleton==null) {
System.out.println("创建了....");
singleton=new LazySingleton2();
}
}
}
return singleton;
}
}
测试结果:
9个线程只创建了一次
这样就只有第一次的时候回效率低了,后面就不会影响了
总结:
主要优点:
1、提供了对唯一实例的受控访问。
2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
3、允许可变数目的实例。
主要缺点:
1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
2、单例类的职责过重,在一定程度上违背了“单一职责原则”。
3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。