单例模式指的是在整个项目中只存在一个该类的实例化,全局公用这个类(即所有的请求都共享这个类)
单例模式的应用场景,比如数据库连接池,线程池(例如处理上传,整个项目限制上传的最大数为1000,则可以将处理上传的线程池设置为单例,队列长度为1000,超过1000提示,稍后上传),dao层的数据库封装类。
单例模式实现方式,饿汉模式(直接放在内存中,类在项目初始化的时候,被创建)和懒汉模式(类在第一次访问的时候,创建,多线程访问的时候存在,线程安全问题),利用类的加载机制,静态内部类(可以实现懒加载,并且线程安全),枚举实现(推荐)
1.饿汉模式
public class SinglePattern {
public static SinglePattern sp= new SinglePattern();
private SinglePattern(){}
public static SinglePattern getInstance(){
return sp;
}
}
2.懒汉式
public class SinglePattern {
public static SinglePattern sp= null;
private SinglePattern(){}
public static SinglePattern getInstance(){
//存在线程安全,多线程访问会同时创建多个SinglePattern
if(sp==null){
sp = new SinglePattern();
}
return sp;
}
}
2.1枷锁的懒汉式(双重校验,实现了懒加载,同时多线访问的时候,只有类没被实例化的时候去创建,synchronized 内置到方法里面,大大的提高程序的执行效率)
public class SinglePattern {
public static SinglePattern sp= null;
private SinglePattern(){}
public static SinglePattern getInstance(){
if(sp==null){
synchronized (SinglePattern.class) {
if(sp==null){
sp = new SinglePattern();
}
}
}
return sp;
}
}
3.0类的加载机制(关键字ststaic,修饰代码块,类被加载的时候,静态代码块被执行)
public class SinglePattern {
public static SinglePattern sp= null;
private SinglePattern(){}
static {
sp = new SinglePattern();
}
public static SinglePattern getInstance(){
return sp;
}
}
4.0静态内部类(静态内部类,懒加载并且线程安全的,与2,3相比从被动加载创建,改为了自己主动创建)
public class SinglePattern {
private static class GetSinglePattern{
final static SinglePattern sp = new SinglePattern();
}
private SinglePattern(){}
public static SinglePattern getInstance(){
return GetSinglePattern.sp;
}
}
以上的4种方式实现单例模式,都是可以通过反射,(如果类实现了序列化接口)反序列化破解,从而创建多个。
反序列化解决办法如下可以在类里面添加
private Object readResolve() {
System.out.println("print from readResolve() method");
return getInstance();
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
System.out.println("print from readObject() method");
ois.defaultReadObject();
}
类级内部类:是指对象内部类有static 关键字修饰
对象级内部类:是指对象内部类没有static关键字修饰
类级内部类,相当于外部对象的static 成员变量,与外部对象没有依赖关系的,类级内部类只能使用外部类的静态属性
对象级内部类,依赖于外部对象,必须外部对象创建后,才能使用
类级内部类相当于外部类的成员变量,只有在第一次使用的时候才会被加载
但是反射是会创建多个对象的
5.枚举类(懒加载,线程安全,并且可以防止反射,反序列化创建多个实例)
public enum EnumSinglePattern{
INSTANCE;
/**
* 自己的业务逻辑
*/
public static void method() {
}
}
项目中如果不考虑资源加载,内存充足的情况可以使用第一种饿汉模式
项目中要实现懒加载,则可以考虑采用4静态内部类
项目中要考虑到单例的安全性和唯一性,使用第5,枚举类
servlet容器启动的时候,所有的java类会被加载到jvm里面,类只会被加载一次,通过new(),反射等方法可以创建多个实例,如果有多个类加载器,都加载了单例类,则单例类会被创建多次,一个加载器创建一次