单例模式:
保证在一个JVM中,只有一个实例存在。保证对象的唯一性
单例的应用场景:
servlet Spring(默认是单例) SpringMVC 连接池 线程池…
单例的好处:
节约内存,重复利用,方便管理
单例的缺点:
线程安全问题。
单例的创建方式
单例有5种创建方式:
1.饿汉式
2.懒汉式
3.静态內部式
4.枚举单例
5.双重检测锁单例
1.饿汉式
//饿汉式单例
public class SingleTon01 {
//类初始化的时候就会创建实例,使用效率高,但是消耗内存
private static final SingleTon01 singleton=new SingleTon01();
//1.构造函数私有化 (同一个类才能访问)
private SingleTon01(){
}
//不存在线程安全问题
private static SingleTon01 getInstance(){
return singleton;
}
//
public static void main(String[] args) {
SingleTon01 instance1=getInstance();
SingleTon01 instance2=getInstance();
System.out.println(instance1==instance2);
}
}
- 懒汉式
//懒汉式
public class SingleTon02 {
//懒汉式单例 实例在被调用的时候才进行创建
private static SingleTon02 singleton;
//获取单例
//存在线程安全。在多线程情况下可能会创建多个实例
//解决方式 使用synchronized修饰 但是效率低下
public static synchronized SingleTon02 getInstance(){
if(singleton==null)
{
singleton=new SingleTon02();
}
return singleton;
}
public static void main(String[] args) {
SingleTon02 singleton1=getInstance();
SingleTon02 singleton2=getInstance();
System.out.println(singleton1==singleton2);
}
}
3.枚举单例
枚举具有单例的特性
先来看看枚举类
Http_200(200,"返回成功");
HttpEnum(Integer httpCode,String message){
this.httpCode=httpCode;
this.message=message;
}
private Integer httpCode;
private String message;
public Integer getHttpCode() {
return httpCode;
}
public void setHttpCode(Integer httpCode) {
this.httpCode = httpCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public static void main(String[] args) {
System.out.println(HttpEnum.Http_200.message);
}
利用枚举的单例特性来生成单例对象
//枚举本身就具有单例性
private SingleTonEnum(){
}
//获取枚举生成实例
public static SingleTonEnum getInstance(){
return singleTon.INSTANCE.getInstance();
}
//定义枚举
static enum singleTon{
INSTANCE;
//定义实例
private SingleTonEnum singleTonEnum;
//利用枚举生成实例
private singleTon(){
singleTonEnum=new SingleTonEnum();
}
//返回实例
public SingleTonEnum getInstance(){
return this.singleTonEnum;
}
}
public static void main(String[] args) {
SingleTonEnum SingleTon1=getInstance();
SingleTonEnum SingleTon2=getInstance();
System.out.println(SingleTon1==SingleTon2);
}
静态内部类
//静态内部类
public class SingletonStatic {
//构造方法私有化
private SingletonStatic(){
System.out.println("SingletonStatic...");
}
//静态内部类生成实例
public static class Singleton{
private static final SingletonStatic singletonStatic=new SingletonStatic();
}
public static SingletonStatic getInstance(){
return Singleton.singletonStatic;
}
public static void main(String[] args) {
SingletonStatic singleton1=getInstance();
SingletonStatic singleton2=getInstance();
System.out.println(singleton1==singleton2);
}
}
双重检验锁
在懒汉的模式上进行双重检验
public SingletonDemo04 getInstance() {
if (singletonDemo04 == null) {
synchronized (this) {
if (singletonDemo04 == null) {
singletonDemo04 = new SingletonDemo04();
}
}
}
return singletonDemo04;
}
如果不需要延迟加载单例,可以使用枚举或者饿汉式,相对来说枚举性好于饿汉式。
如果需要延迟加载,可以使用静态内部类或者懒韩式,相对来说静态内部类好于懒汉式。
单例防止反射漏洞攻击
在构造函数中,只能允许初始化化一次即可。
private static boolean flag = false;
private SingletonDemo04() {
if (flag == false) {
flag = !flag;
} else {
throw new RuntimeException("单例模式被侵犯!");
}
}
public static void main(String[] args) {
}