- 创建型模式: – 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
- • 结构型模式: – 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模 式。
- • 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模 式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
1.单例模式:
1):核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问
2):常见的五种单例模式实现方式 :
1.饿汉式(线程安全,调用效率高。 但是,不能延时加载。)
2.懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)
3.双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题。不建议使用)
4.静态内部类式(线程安全,调用效率高。 但是,可以延时加载)
5.枚举式(线程安全,调用效率高,不能延时加载。并且可以天然的防止反射和反序列 化漏洞!)
2.代码演示:
1.饿汉:
package com.example.shejimoshi.singleton;
/**
* 单例模式之饿汉模式
*/
public class SingleTonDemo {
//类初始化时立即加载(没有延时加载的优势)加载类时 天然是线程安全的
private static SingleTonDemo s = new SingleTonDemo();
//构造方法私有化
private SingleTonDemo()
{
}
//提供一个公开的外部访问点 调用效率高
public static SingleTonDemo getS()
{
return s;
}
}
2.懒汉式
package com.example.shejimoshi.singleton;
/**
* 单例模式之懒汉式
*/
public class SingleTonDemo1 {
//类初始化时 不初始化这个对象 延时加载 正在用的时候再创建 资源利用效率低
private static SingleTonDemo1 s1;
//构造方法私有化
private SingleTonDemo1()
{
}
//提供一个公开的外部访问点 方法同步 但是调用效率低 因为并发访问需要等待
public static synchronized SingleTonDemo1 getS1()
{
if(s1==null)
{
s1= new SingleTonDemo1();
}
return s1;
}
}
- 静态内部类式
package com.example.shejimoshi.singleton;
/**
* 单例模式之静态内部类
*兼备了并发高效调用和延迟加载的优势
*/
public class SingleTonDemo3 {
//构造方法私有化
private SingleTonDemo3()
{
}
//静态内部类 加载类时是线程 安全的
private static class SingletonClassInstance
{
private static final SingleTonDemo3 s =new SingleTonDemo3();
}
public static SingleTonDemo3 getS3()
{//只有真正调用getS3,才会加载静态内部类
return SingletonClassInstance.s;
}
}
- 枚举式:
package com.example.shejimoshi.singleton;
/**
* 单例模式之枚举方式实现
* 唯一的遗憾是没有懒加载 就是延时加载
*/
public enum SingleTonDemo4 {
//这个枚举元素 本身就是单例模式
INSTENCE;
/**
* 添加自己需要的操作
*/
public void singletonOperation()
{
}
}
3.如何选择:
4.使用反射跳过单例模式 (测试针对懒汉模式):
package com.example.shejimoshi.singleton;
import java.lang.reflect.Constructor;
/**
* 测试使用反射破解单例
*/
public class Test1 {
public static void main(String[] args) throws Exception {
//反射
Class clazz= (Class)Class.forName("com.example.shejimoshi.singleton.SingleTonDemo5");
Constructor c= clazz.getDeclaredConstructor(null);
//跳过认证 可以访问私有的方法
c.setAccessible(true);
SingleTonDemo5 s1= c.newInstance();
SingleTonDemo5 s2= c.newInstance();
System.out.println(s1);
System.out.println(s2);
}
}
执行结果:很显然通过反射没有走单例模式
5.单例模式怎么防止 使用反射跳过单例模式 (测试针对懒汉模式)
package com.example.shejimoshi.singleton;
/**
* 单例模式之懒汉式(测试反射漏洞)
*/
public class SingleTonDemo5 {
//类初始化时 不初始化这个对象 延时加载 正在用的时候再创建 资源利用效率低
private static SingleTonDemo5 s1;
//构造方法私有化
private SingleTonDemo5()
{
//加上次代码可防止反射跳过 单例
if (s1!=null)
{
throw new RuntimeException();
}
}
//提供一个公开的外部访问点 方法同步 但是调用效率低 因为并发访问需要等待
public static synchronized SingleTonDemo5 getS1()
{
if(s1==null)
{
s1= new SingleTonDemo5();
}
return s1;
}
}
6.通过反序列化来创建多个对象来破解单例:
package com.example.shejimoshi.singleton;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
/**
* 测试使用反序列化破解单例
*/
public class Test2 {
public static void main(String[] args) throws Exception {
SingleTonDemo5 s1 =SingleTonDemo5.getS1();
SingleTonDemo5 s2 =SingleTonDemo5.getS1();
System.out.println(s1);
System.out.println(s2);
//使用反序列化来创建多个对象 (针对懒汉模式)
//首先 要反序列化的类要实现 Serializable接口
//把对象写入硬盘
FileOutputStream fos =new FileOutputStream("d:/a.txt");
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(s1); //把s1对象写入硬盘
oos.close();
fos.close();
//从硬盘中读取
ObjectInputStream ois =new ObjectInputStream(new FileInputStream("d:/a.txt"));
SingleTonDemo5 s3 =(SingleTonDemo5) ois.readObject();
System.out.println(s3);
}
}
执行结果:显然反序列化后的对象改变了 违反了 单例
7.怎么防止反序列化 破解
package com.example.shejimoshi.singleton;
import java.io.Serializable;
/**
* 单例模式之懒汉式(测试反射漏洞)
*/
public class SingleTonDemo5 implements Serializable {
//类初始化时 不初始化这个对象 延时加载 正在用的时候再创建 资源利用效率低
private static SingleTonDemo5 s1;
//构造方法私有化
private SingleTonDemo5()
{
//加上次代码可防止反射跳过 单例
if (s1!=null)
{
throw new RuntimeException();
}
}
//提供一个公开的外部访问点 方法同步 但是调用效率低 因为并发访问需要等待
public static synchronized SingleTonDemo5 getS1()
{
if(s1==null)
{
s1= new SingleTonDemo5();
}
return s1;
}
//反序列化时 如果定义了次方法 直接返回此方法的对象 防止反序列化破解
private Object readResolve()
{
return s1;
}
}
执行结果:
8.使用CountDownLatch同步辅助类测试效率:
package com.example.shejimoshi.singleton;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.concurrent.CountDownLatch;
/**
* 测试多线程环境下各种环境的效率
*/
public class Test3 {
public static void main(String[] args) throws Exception {
//获取当前时间的时间戳
long start =System.currentTimeMillis();
int threadNum =10;
CountDownLatch countDownLatch =new CountDownLatch(threadNum);
for (int i=0;i
除了懒汉都还可以。