目录
什么是单例模式?
定义
单例模式的主要特点
单例模式的几种设计模式
1.懒汉式:线程不安全
2.懒汉式:线程安全
3.饿汉式
4.双重校验锁
单例模式的优缺点
优点:
缺点:
适用场景:
什么是单例模式?
定义
单例模式(Singleton Pattern)是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点以供外部代码使用。
单例模式的主要特点
保证了类只有一个实例。由于只有一个实例存在,因此可以避免多个实例之间的冲突。
提供了一个全局访问点。通过单例模式,可以在任何需要时访问该类的唯一实例,方便调用和使用。
能够解决频繁创建和销毁全局使用的类实例的问题。(如果一个对象已经被创建了,那么以后每次请求该对象时,都会直接返回之前创建好的对象实例,避免了重复创建和销毁对象的开销,提高系统性能。)
单例模式的几种设计模式
懒汉式:在首次使用时创建实例。
饿汉式:在类加载时就创建实例。
双重校验锁:采用双锁机制,安全且在多线程情况下能保持高性能。
1.懒汉式:线程不安全
这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式
public class LanHan {
private LanHan(){}
private static LanHan lanHan;
public static LanHan getLanHan(){
if(lanHan==null){
lanHan = new LanHan();
}
return lanHan;
}
public void sayHello(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
LanHan lanHan = LanHan.getLanHan();
lanHan.sayHello();
}
}
2.懒汉式:线程安全
这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
public class LanHan {
private LanHan(){}
private static LanHan lanHan;
public static synchronized LanHan getLanHan(){
if(lanHan==null){
lanHan = new LanHan();
}
return lanHan;
}
public void sayHello(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
LanHan lanHan = LanHan.getLanHan();
lanHan.sayHello();
}
}
3.饿汉式
这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
public class EHan {
private EHan(){}
private static EHan eHan = new EHan();
public static EHan getEHan(){
return eHan;
}
public void syHello(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
LanHan lanHan = LanHan.getLanHan();
lanHan.sayHello();
EHan eHan = EHan.getEHan();
eHan.syHello();
}
}
4.双重校验锁
这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class DoubleLock {
private static volatile DoubleLock doubleLock;
private DoubleLock(){}
public static DoubleLock getDoubleLock(){
if(doubleLock==null){
synchronized (DoubleLock.class){
doubleLock = new DoubleLock();
}
}
return doubleLock;
}
public void sayHello(){
System.out.println("hello world");
}
}
public class Test {
public static void main(String[] args) {
LanHan lanHan = LanHan.getLanHan();
lanHan.sayHello();
EHan eHan = EHan.getEHan();
eHan.syHello();
DoubleLock.getDoubleLock().sayHello();
}
}
单例模式的优缺点
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
适用场景:
需要全局访问和管理的资源,可以确保资源的唯一性和一致性。
例如:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。