单例模式
:是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。单例模式是创建型模式
- 懒汉式单例模式:在类加载的时候就立即初始化,并且创建为单例对象,它绝对线程安全,线程还没出现的时候就实例化了
- 不可能存在访问安全问题。
- 优点:没有加任何锁,执行效率比较高,用户体验比懒汉式单例模式更好
- 缺点:类加载的时候就初始化,不管用不用都占着空间,浪费了内存。
饿汉式:
public class HungrySingleton {
private static HungrySingleton hungrySingleton=new HungrySingleton();
//另一种写法
private static HungrySingleton hungrySingleton1;
static{
hungrySingleton1=new HungrySingleton();
}
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
懒汉式:
/**
* 特点:被外部类调用的时候,内部类才会被加载.缺点:线程不安全
*/
public class LazySingleton {
private LazySingleton(){}
private static LazySingleton lazySingleton=null;
public static LazySingleton getInstance(){
if (lazySingleton==null){
lazySingleton=new LazySingleton();
}
return lazySingleton;
}
//方法一:线程不安全的办法,加锁,缺点:性能下降
public static synchronized LazySingleton getInstance1(){
if (lazySingleton==null){
lazySingleton=new LazySingleton();
}
return lazySingleton;
}
//方法二:双重检验所:解决线程安全和性能问题(双重检验锁)
public static LazySingleton getInstance2(){
if(lazySingleton==null){
synchronized (LazySingleton.class){
if(lazySingleton==null){
lazySingleton=new LazySingleton();
//1、分配内存给这个对象
//2、初始化对象
//3、设置lazysingleton指向刚分配的内存地址
}
}
}
return lazySingleton;
}
}
内部类:
package com.wanda.singleton;
import java.lang.reflect.Constructor;
/**
* 这种形式兼顾了饿汉式内存浪费问题和synchronized性能问题
*/
public class LazyInnerSingleton {
// private LazyInnerSingleton(){}
//修改后的构造方法
private LazyInnerSingleton(){
if(LazyHolder.lazy!=null){
throw new RuntimeException("不允许创建多个实例");
}
}
public static final LazyInnerSingleton getInstance(){
return LazyHolder.lazy;
}
//内部类在方法调用之前初始化,避免了线程不安全的问题
private static class LazyHolder{
private static final LazyInnerSingleton lazy=new LazyInnerSingleton();
}
public static void main(String[] args) {
//反射破坏单例情况,通过这种方式会创建两个不同的单例。可以在构造方法中做一些限制,一旦多次重复创建就抛出异常。
try {
Class<?> clazz=LazyInnerSingleton.class;
Constructor constructor=clazz.getDeclaredConstructor(null);
//强制访问
constructor.setAccessible(true);
Object o1=constructor.newInstance();
Object o2=constructor.newInstance();
System.out.println(o1==o2);
}catch (Exception e){
e.printStackTrace();
}
}
}
序列化破坏单例
package com.wanda.singleton;
import java.io.*;
//一个单例对象创建后,有时需要序列化到磁盘,下次使用时在从磁盘读入,进行反序列化,反序列华的对象会重新分配内存
//即重新创建,如果序列化的对象是单例,就违背了单例的意义。
public class SeriableSingleton implements Serializable {
public static final SeriableSingleton INSTANCE=new SeriableSingleton();
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
private Object readResolve(){
return INSTANCE;
}
public static void main(String[] args) {
SeriableSingleton s1=null;
SeriableSingleton s2=SeriableSingleton.getInstance();
FileOutputStream fos=null;
try {
fos=new FileOutputStream("seriablesingleton.obj");
ObjectOutputStream os=new ObjectOutputStream(fos);
os.writeObject(s2);
os.flush();
os.close();
FileInputStream fis=new FileInputStream("seriablesingleton.obj");
ObjectInputStream ois=new ObjectInputStream(fis);
s1=(SeriableSingleton) ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1==s2);//false 解决方法:加上readResolve方法
}catch (Exception e){
}
}
}
枚举:
package com.wanda.singleton;
import java.io.*;
//一个单例对象创建后,有时需要序列化到磁盘,下次使用时在从磁盘读入,进行反序列化,反序列华的对象会重新分配内存
//即重新创建,如果序列化的对象是单例,就违背了单例的意义。
public class SeriableSingleton implements Serializable {
public static final SeriableSingleton INSTANCE=new SeriableSingleton();
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
private Object readResolve(){
return INSTANCE;
}
public static void main(String[] args) {
SeriableSingleton s1=null;
SeriableSingleton s2=SeriableSingleton.getInstance();
FileOutputStream fos=null;
try {
fos=new FileOutputStream("seriablesingleton.obj");
ObjectOutputStream os=new ObjectOutputStream(fos);
os.writeObject(s2);
os.flush();
os.close();
FileInputStream fis=new FileInputStream("seriablesingleton.obj");
ObjectInputStream ois=new ObjectInputStream(fis);
s1=(SeriableSingleton) ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1==s2);//false 解决方法:加上readResolve方法
}catch (Exception e){
}
}
}
容器式:
package com.wanda.singleton;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 容器式单例模式:非线程安全
*/
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> map=new ConcurrentHashMap<>();
public static Object getBean(String clazzName){
synchronized (map){
if(!map.containsKey(clazzName)){
Object obj=null;
try{
obj=Class.forName(clazzName).newInstance();
map.put(clazzName,obj);
}catch (Exception e){
e.printStackTrace();
}
return obj;
}else{
return map.get(clazzName);
}
}
}
}