※单例模式
一.单例模式五种创建方式
1.饿汉式
特点:线程安全,调用效率高,但不能延时加载
public class SingletonDemo01 {
// 静态实例,在类加载时初始化,虚拟机保证只装载一次
//肯定不会有并发访问的问题,不需要synchronized,线程安全
private static SingletonDemo01 singleton = new SingletonDemo01();
// 构造器私有
private SingletonDemo01() {
}
// 公有获取实例的方法。如果没有调用该方法,会造成资源浪费
public static /*synchronized*/ SingletonDemo01 getInstence() {
return singleton;
}
}
2.懒汉式
特点:线程安全,调用效率不高,但是可以延时加载
public class SingletonDemo02
{
private static SingletonDemo02 instence;
private SingletonDemo02()
{
}
//线程安全,效率低
public static synchronized SingletonDemo02 getInstence()
{
if (instence == null)
{
instence = new SingletonDemo02();
}
return instence;
}
}
3.双重检测锁式
public class SingletonDemo03
{
private static SingletonDemo03 instence = null;
private SingletonDemo03()
{}
/**
* 双重锁检查式:提高了执行效率,不必每次获取对象都进行同步
* 第一次同步创建之后就没有必要了
*
* 问题:由于编译器优化和JVM底层内部模型的原因
* 偶尔会出问题,不建议使用
*/
public static SingletonDemo03 getInstence()
{
if(instence == null)
{
SingletonDemo03 singletonDemo03;
synchronized(SingletonDemo03.class)
{
singletonDemo03 = instence;
if(singletonDemo03 == null)
{
synchronized (SingletonDemo03.class)
{
if(singletonDemo03 == null)
{
singletonDemo03 = new SingletonDemo03();
}
}
}
instence = singletonDemo03;
}
}
return instence;
}
}
----------------------------------------------------------------
public class SingletonClass {
private volatile static SingletonClass instance = null;
public static SingletonClass getInstance() {
if (instance == null) {
synchronized (SingletonClass.class) {
if(instance == null) {
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
4.静态内部类式
特点:线程安全,调用效率高,可延时加载
-
/** * 同时具备 懒加载、调用效率高、线程安全的特点 * @author lp */ public class SingletonDemo04 { private static class SingletonClassInstence { //instence是static final类型的,保证了内存中只有一个实例存在, //而且只被赋值一次,从而保证了线程安全 private static final SingletonDemo04 instence = new SingletonDemo04(); } //调用到该方法的时候,才会去加载静态内部类,对instence进行初始化 //加载类时是线程安全的 public static SingletonDemo04 getInstence() { return SingletonClassInstence.instence; } private SingletonDemo04() {} }
5.枚举单例
特点:线程安全,调用效率高,不能延时加载
/**
* 优点:
* 1.实现简单;
* 2.枚举本身就是单例,由JVM提供保障,避免通过反射和反序列化创建单例对象
* 缺点:
* 不可以延迟加载
* @author lp
*/
public enum SingletonDemo05
{
/**
* 定义一个枚举元素(枚举天然单例),代表Singleton的一个实例
*/
INSTENCE;
public void singletonOperation()
{
//功能处理
}
}
单例模式三个重要的特性:延迟加载、调用效率高、线程安全。具体选择哪一种方式,可以根据这个规则来
不需要延时加载:枚举式好于饿汉式
需要延时加载:静态内部类式好于懒汉式
以上都是线程安全的创建方式
二. 反射和反序列化漏洞防止
1.通过反射机制可以获取单例模式的私有构造器constructor,
constructor.setAccessible(true) ;constructor.newInstense()就可以创建新的对象。破坏了单例模式。
可以通过在constructor的构造器中添加异常的方式来阻止创建:
if(instense != null){throw new runtimeException();}
2. 反序列化方式破解单例
添加方法(反序列化的时候会自动调用该方法)
private Object readResolve() throw ObjectStreamInputException{ return instense;}
※工厂模式
1.简单工厂模式
通过简单工厂类,完成对象的新建。可以是if...else 的形式,也可以是static 方法。将修改代码独立出来
2.工厂
创建对象的代码,不同类型有不同的创建不步骤,定义成abstract,由子类各自决定。
3.抽象工厂
产品族:多个接口对应的类。
※ 建造者模式
建造者模式有四个角色:
(1) abstractBuilder: 指定了具体建造者要实现的接口(要创建组成Product的零部件的方法)
(2) concreteBuilder:实现abstractBuilder中接口方法,具体创建组成Product的零部件;提供获取创建好的Product的方法
(3) Product: 表示要构造的复杂对象,concreteBuilder中通过抽象方法构建了各个部件,最后通过一个方法返回组装好的Prodcut
(4) Director: 在director中new一个builder对象,builder对象依次调用构建零部件的方法,最后调用获取Product的方法
※原型模式
实现Cloneable接口的对象,通过clone()方法创建一个新的实例。
一般用在创建对象比较耗时的场景中,根据需要可以对其中的属性进行修改。