单例模式的饿汉式和懒汉式的实现以及⽐较它们的区别⽐较(Java实现)
单例模式是应⽤的⽐较多的⼀种设计模式,也是⾯试时⽐较喜欢问的⼀种,这篇⽂章就带你学习⼀边单例模式的最基本的两种实现⽅式吧
饿汉式
顾名思义,饿汉式实现就是在类加载时就创建好了,不必等到调⽤获取实例⽅法的时候才创建对象,调⽤⽅法时直接返回就可以了。
public class HungrySingleton {
// ⼀开始就获取了实例
private static HungrySingleton singleton =new HungrySingleton();
// 构造⽅法私有,外部⽆法构造
private HungrySingleton(){}
// 公有向外提供
public static HungrySingleton getSingleton(){
return singleton;
}
}
测试⽅法
public class Test1 {
public static void main(String[] args){
HungrySingleton s1 = Singleton();
HungrySingleton s2 = Singleton();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
}
}
HungrySingleton@16d3586
HungrySingleton@16d3586
true
由上⾯的输出结果可知确实实现了饿汉式单例模式。下⾯来看看懒汉式单例模式
懒汉式
这个也可以顾名思义,和饿汉式恰好相反,对象实例是在⽅法中才创建的。
public class LazySingleton {
private static LazySingleton singleton = null;
private LazySingleton(){}
单例模式的几种实现方式// 在⽅法⾥才实例化
public static LazySingleton getSingleton(){
if(singleton == null){
singleton =new LazySingleton();
}
return singleton;
}
}
LazySingleton@16d3586
LazySingleton@16d3586
从测试的代结果中也可以看出,确实是获取了同⼀个对象,那么这两种模式有什么区别呢
1.懒汉式默认不会实例化,要等到外部调⽤⽅法时才会,饿汉式⼀开始就实例化了对象
2.线程安全上,饿汉式肯定是线程安全的,因为在线程没出现之前就实例化了对象,懒汉式则是线程不安全的,因为在多线程下,如果⼀个线程判断完实例为null就休眠或着中断,那么另⼀个线程也进⼊⽅法,判断实例也为null,那么该线程就会创建实例对象,⽽原来的那个休眠线程恢复以后,直接就执⾏实例化new对象这⼀步,那么就会出现多个实例。 下⾯来通过例⼦验证⼀下
public static void main(String[] args){
// 饿汉式
new Thread(()->{
System.out.Singleton());
}).start();
new Thread(()->{
System.out.Singleton());
}).start();
new Thread(()->{
System.out.Singleton());
}).start();
}
饿汉式我开启了三个线程去获取对象,得到的都是同⼀个对象
HungrySingleton@1797c69
HungrySingleton@1797c69
HungrySingleton@1797c69
懒汉式下我开启了四个线程去获取对象,结果出现了⼀个与其它不同的对象,说明懒汉式确实是线程不安全的
LazySingleton@1797c69
LazySingleton@1ca79ec
LazySingleton@1ca79ec
LazySingleton@1ca79ec
那么有没有⽅法去实现线程安全的懒汉式单例呢,⾸先最容易的就是加锁了,⽤synchronized关键字
public static synchronized LazySingleton getSingleton()
// 在get⽅法中添加synchronized关键字,我开了⼆⼗个线程去执⾏,结构得到的都是同⼀个对象
// 除了可以在⽅法头添加关键字,还可以在代码块⾥添加,具体的效果和这个⼏乎是完全⼀样
那么问题来了,这样是不是就解决懒汉式线程安全的问题了呢,熟悉锁机制的朋友应该知道这样会使程序的运⾏效率⼤打折扣。
3.分析上⾯的线程安全,接下来就是性能了,可能你已经想到了,饿汉式不需要加锁,执⾏效率⾼,懒汉式需要加锁,执⾏效率低
4.占⽤内存上,饿汉式不管你⽤不⽤到它的实例对象,他⼀开始就已经实例化在那⾥了,占据了内存空间,⽽懒汉式等到⽤的时候才实例化,不会浪费内存
那来个表格总结⼀下吧
饿汉式懒汉式
实例化⼀开始就实例化等到要⽤的时候才实例化
线程安全安全不安全,需要加锁
性能效率⾼效率低
占⽤内存有可能会浪费不会浪费
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论