设计模式笔记———单例模式
一、定义
单例模式:这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 单例类只能有一个实例
- 2.单例类必须自己创建自己的唯一实例
- 3.单例类必须为其他对象提供这唯一实例
二、代码实现
- 饿汉式
/**
1. 饿汉式
*/
public class Singleton1 {
private Singleton1(){};
private static Singleton1 instance = new Singleton1();
public static Singleton1 getInstance(){
System.out.println("加载饿汉式");
return instance;
}
}
- 懒汉式
/**
1. 懒汉式
*/
public class Singleton2 {
private Singleton2() {
}
private static Singleton2 instance;
public static Singleton2 getInstance(){
if (instance==null){
System.out.println("懒汉式")
instance = new Singleton2();
}
return instance;
}
}
三、懒汉式与饿汉式区别
- 饿汉式:
/**
*是否 Lazy 初始化:否
*是否多线程安全:是
*实现难度:易
*描述:这种方式比较常用,但容易产生垃圾对象。
*优点:没有加锁,执行效率会提高。
*缺点:类加载时就初始化,浪费内存。
*它基于 classloder 机制避免了多线程的同步问题,
* 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
* 在单例模式中大多数都是调用 getInstance 方法,
* 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
* 这时候初始化 instance 显然没有达到 lazy loading 的效果。
*/
懒汉式:
/**
*是否 Lazy 初始化:是
*是否多线程安全:否
*实现难度:易
*描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。
*因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
*这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
*/
- 饿汉式天生线程安全,可以直接用于多线程而不会出现问题;
懒汉式本身并非线程安全,为了实现线程安全有几种写法。
如:
/**
* 线程安全懒汉式
*/
public class Singleton3 {
private Singleton3() {
}
private static Singleton3 instance;
public static synchronized Singleton3 getInstance(){
if (instance==null){
return new Singleton3();
}
return instance;
}
}
或
/**
* 线程安全懒汉式第二种写法
*/
public class Singleton4 {
//私有化构造方法,防止外界调用,保证对象是单例对象
private Singleton4(){};
// 私有化静态变量,防止外界修改,没有实例化
private static Singleton4 instance;
//提供方法给外界调用获得单例对象
//当多个线程都在调用此方法是时,必须只有一个单例对象生成,
//这里采用加上同步代码块
public static Singleton4 getInstance(){
if (instance==null){
//静态方法,是当前类为进程锁
synchronized(Singleton4.class){
return new Singleton4();
}
}
return instance;
}
}
如果不想加锁,又不想太过于消耗内存,可以
public class Singleton5 {
/**
1. 折中写法,不加锁(即保证线程安全)也不太消耗内存
2. (饿汉式消耗内存,懒汉式不保证线程安全)
3.
4. 这个时候就需要一个内部类作为桥梁了,当getInstance()时,
5. 类加载器才会去加载Nested,然后实例化Singleton的实例
*/
private Singleton5(){
}
public static Singleton5 getInstance(){
return Nested.singleton;
}
public static class Nested{
static {
System.out.println("蛤蛤");
}
private static Singleton5 singleton = new Singleton5();
}
}
- 资源加载和性能
饿汉式在创建时就实例化出一个静态对象,不管会不会使用这个对象,都会占据一定内存,但是对应的,在第一次调用时速度也会快很多,因为其资源已经完成初始化。
懒汉式有延迟加载,在第一次使用该实例才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样。

浙公网安备 33010602011771号