介绍
- 作用:保证类只有一个对象,并提供一个访问该实例的方法
- 应用场景:任务管理器,读取配置文件的类,日志管理,数据库连接池等
- 优点:避免全局使用的类频繁创建与销毁,节省系统资源与内存开销
- 缺点:构造器私有后不能继承
实现方式(线程安全)
class SingleInstance{
private static SingleInstance instance=null;
private SingleInstance(){};
public synchronized static SingleInstance getInstance(){
if(instance==null){
instance=new SingleInstance();
}
return instance;
}
}
class SingleInstance{
private static SingleInstance instance=new SingleInstance();
private SingleInstance(){};
public static SingleInstance getInstance(){
return instance;
}
}
class SingleInstance{
private static SingleInstance instance=null;
private SingleInstance(){};
public static SingleInstance getInstance(){
if(instance==null){
synchronized(SingleInstance.class){
if(instance==null){
instance=new SingleInstance();
}
return instance;
}
}
return instance;
}
}
class SingleInstance{
private SingleInstance(){}
private static class Instance{
private static final SingleInstance instance=new SingleInstance();
}
public static SingleInstance getInstance(){
return Instance.instance;
}
}
- 枚举:调用效率高,不能延时加载,但是可以防止反射,反序列化
pubic enum SingleInstance{
INSTANCE;
public void operation(){}
}
防反射
public class MyLearn {
public static void main(String[] args) throws Exception {
SingleInstance instance1 = SingleInstance.getInstance();
SingleInstance instance2 = SingleInstance.getInstance();
System.out.println(instance1);
System.out.println(instance1);
Class<SingleInstance> clazz = (Class<SingleInstance>) Class.forName("learn.SingleInstance");
Constructor<SingleInstance> constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
SingleInstance instance3 = constructor.newInstance();
SingleInstance instance4 = constructor.newInstance();
System.out.println(instance3);
System.out.println(instance4);
}
}
class SingleInstance{
private static SingleInstance instance=new SingleInstance();
private SingleInstance(){
if(instance!=null){
throw new RuntimeException();
}
};
public static SingleInstance getInstance(){
return instance;
}
}
防反序列化
public class MyLearn {
public static void main(String[] args) throws Exception {
SingleInstance instance1 = SingleInstance.getInstance();
FileOutputStream fos = new FileOutputStream("f:/instace.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(instance1);
oos.close();
fos.close();
FileInputStream fis = new FileInputStream("f:/instace.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
SingleInstance instance2 = (SingleInstance) ois.readObject();
fis.close();
ois.close();
System.out.println(instance1);
System.out.println(instance2);
}
}
class SingleInstance implements Serializable {
private static SingleInstance instance = new SingleInstance();
private SingleInstance() {
if (instance != null) {
throw new RuntimeException();
}
};
public static SingleInstance getInstance() {
return instance;
}
private Object readResolve() throws ObjectStreamException{
return instance;
}
}
多线程环境测试
public class MyLearn {
public static void main(String[] args) throws Exception {
CountDownLatch count=new CountDownLatch(100);
long start = System.currentTimeMillis();
for(int i=0;i<100;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<100000;j++){
SingleInstance instance=SingleInstance.getInstance();
}
count.countDown();
}
}).start();
}
count.await();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
}
- 效率比较:单例对象占用资源小,不需要延时加载,使用枚举方式好于饿汉式;单例对象占用资源大,需要延时加载,使用静态内部类方式好于懒汉式。