单例设计模式:
所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个实例对象。
那么如何实现上述单例设计模式呢?
实现步骤:
- 首先创建私有化构造器
- 在内部创建对象,相当于这个类的属性
- 使用公共的、静态的方法返回内部已创建的对象
注:使用下述逻辑或许可帮助记忆
- ∵ 单例模式,在外部只能有一个对象,即避免使用
对象.方法
创建多个对象。∴ 将构造器声明为private
的,让其无法在外部创建对象,并事先在类内部创建好对象,调用对应方法,将创建好的对象返回出去。 - ∵ 要调用类中的方法,又无法在外部创建对象,即不能通过
对象.方法
的方式调用。∴ 将返回对象的方法声明为static
,这便可使用类.方法
返回内部创建的对象。 - ∵ 返回对象声明的方法是
static
的,而static
的方法只能调用static
的对象。∴ 事先创建的对象也必须是static
的。
🍔🍟🍗方法一:饿汉式
class Hungry{
// 对应1
private Hungry(){
}
// 对应2(声明和初始化)
// 由于方法是static的,静态的方法只能调用静态的对象,需将创建对象声明为static
private static Hungry hungry = new Hungry();
// 对应3
// 由于构造器是私有的,不能通过对象.方法的方式调用,需将方法声明为static,使用类名.方法调用
public static Hungry getInstance(){
return hungry;
}
}
🐷🐷🐷方法二:懒汉式
- 线程不安全
class Lazy{
//对应1
private Lazy(){
}
//对应2 (声明 但不初始化)
// 由于方法是static的,静态的方法只能调用静态的对象,需将创建对象声明为static
private static Lazy lazy; // <——区别
//对应3
// 由于构造器是私有的,不能通过对象.方法的方式调用,需将方法声明为static,使用类名.方法调用
public static Lazy getInstance(){
// 暂时是线程不安全的
if (lazy == null){
lazy = new Lazy();
}
return lazy;
}
}
- 线程安全(方式1)
class Lazy {
private Lazy(){
}
private static Lazy lazy= null;
public static Lazy getInstance(){
// 方式1:效率稍差
synchronized(Lazy.class){
if(lazy == null){
lazy = new Lazy();
}
return lazy;
}
}
}
- 线程安全(方式2)
class Lazy {
private Lazy(){
}
private static Lazy lazy= null;
public static Lazy getInstance(){
// 方式2: 效率较高
if(lazy == null){
// 后面的线程不用一个一个过锁,直接拿到实例就return
synchronized(Lazy.class){
if (lazy == null){
lazy = new Lazy();
}
}
}
return lazy;
}
}
两种实现方法的区别
饿汉式
-
优点:天然线程安全
-
缺点:对象加载时间过长,占用内存
懒汉式
-
优点:用的时候才创建对象(延迟对象创建),节省内存
-
缺点:目前的写法是线程不安全的(需要改进才能变为线程安全的)
后续
学完多线程,再补充线程安全的懒汉式
- (已补充线程安全代码:2020.1.15)