设计模式-单例模式
定义: 只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
运用场景: 数据库连接池,文件系统,应用配置等。
优缺点:
- 某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
- 省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
- 有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
种类:
- 饿汉模式
- 懒汉模式
特点:
- 单例只能有一个实例(即构造方法必须为私有的即private)
- 单例必须自己给自己创建一个能够保证唯一性的实例
- 单例必须提供一个共有的方法来返回它自己的唯一实例
饿汉模式介绍:
依据的原理:根据JLS(Java Language Specification)中的规定,一个类在一个ClassLoader中只会被初始化一次,这点是JVM本身保证的
因此创建后就不会有多例的问题。
优点:
1. 创建方便
2. 效率高
缺点:
1. 对内存的使用量较大
应用场景:适用于小对象,对于过于大的对象就应该考虑适用懒汉时的了。
以下上饿汉模式的代码:
public class Singleton {
private Singleton(){}
private static final Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
懒汉模式介绍:
懒汉模式,适用于所有的应用场景,但是要做过多的判断,相对来说它会影响程序的运行性能。
优点:
1.适用于所有的应用场景
2.使用时占内存较小(只有在使用的时候才会被创建)
缺点:
1.性能较低
2.书写较为繁琐
先看看一个简单的懒汉式例子:
private Singleton(){}
private static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
懒汉变种:
//饱汉模式
class Singleton{
/*持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private static Singleton instance = null;
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
//此处存在线程安全问题
// public static Singleton getInstance(){
// if(instance ==null ){
// instance = new Singleton();
// }
// return instance;
// }
// 加上sync 关键字,可以保证了同步,但是锁整个方法消耗性能(因为也就创建实例的时候加锁,以后都不需要了,但是每次调用的时候都要用到这个加锁方法,影响性能),所以使用同步代码块
// public synchronized static Singleton getInstance(){
// if(instance ==null ){
// instance = new Singleton();
// }
// return instance;
// }
// 使用同步代码也会导致线程不安全,因为 new Singleton 和 return instance 应该是一起的,破坏了原子性,所以一样有问题
// public static Singleton getInstance(){
// if(instance ==null ){
// synchronized (Singleton.class) {
// instance = new Singleton();
// }
// }
// return instance;
// }
//Double Check Locking 双检查锁机制(推荐) ,即可保证线程安全性-->这样写还是有时候会出现问题,内存模型允许所谓的“无序写入”。。,(具体请看 java内存模型,把instance 加入volitate 就变成了线程安全)
public static Singleton getInstance(){
if(instance ==null ){
synchronized (Singleton.class) {
if(instance==null){
instance = new Singleton();
}
}
}
return instance;
}
//使用 静态内部类的方式 ,, 这样就可以避免线程安全问题,当要使用到 这个单利的时候,才会去加载静态内部类,而且所有线程都在外面等待,单例对象new出来
public static Singleton getInstance2(){
return InnerClass.instance;
}
static class InnerClass{
private static Singleton instance = new Singleton();
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve() {
return instance;
}
}
//**********************************************************************************************************************//
//饥汉模式
class Singleton2{
//类加载时候就创建实体类
private static Singleton2 sing = new Singleton2();
//私有化构造器
private Singleton2(){
}
public static Singleton2 getInstance(){
return sing;
}
}