系列文章目录
java模式之单例模式
文章目录)
前言
String类是java中常用的一种类。
一、单例模式的定义:
单例模式是一种常见的软件设计模式。其核心结构中只包含一个被称为单例的特种类,以保证系统中该类只有一个实例,并且自行实例化并向整个系统提供这个实例。这一点有时是十分重要的。
二、单例模式的特点
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式保证了全局对象的唯一性,一个类仅有一个对象。
三.单例模式的实现方法
实现方法主要为两种:饿汉式和懒汉式
1.饿汉式单例
:先创建对象再使用
实现步骤:
1.构造器私有化
2.在类的内部创建对象
3.向外提供一个静态的公共方法,返回对象
**
* @author :飞天の鱼
* @date : 2022/5/12 17:19
*/
public class Singleton {
//1.构造器私有化
private Singleton() {
}
//2.在类的内部创建对象
private static final Singleton singleton = new Singleton();
//3.提供一个方法,用于返回对象
public static Singleton getInstance(){
return singleton;
}
}
缺点:
因为先创建对象,如果对象未被使用会造成资源的浪费
2.懒汉式单例
:第一次使用时再进行实例化(创建对象)
实现步骤:
1.构造器私有化
2.在类的内部定义一个静态对象
3.向外提供一个静态的公共方法,返回对象
(但会对对象进行判断,看是否进行实例化)
class Singleton1 {
//1.构造器私有化
private Singleton1() {
}
//2.在类的内部定义一个静态对象
private static Singleton1 singleton1 = null;
//如不给对象赋值默认对象为null
//3.向外提供一个静态的公共方法,返回对象
public static Singleton1 getInstance(){
if (singleton1 == null){
singleton1 = new Singleton1();
}
return singleton1;
}
}
缺点:
懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个实例
3.两种方式的异同
图示如下
四.关于线程安全的问题
解决方法:
由于实现方式同步效率太低,所以摒弃同步方法,改为同步产生实例化的的代码块。
1、在getInstance方法上加同步
1、在getInstance方法上加同步
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
2、双重检查锁定
Double-Check概念对于多线程开发者来说不会陌生,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。
优点:线程安全;延迟加载;效率较高。
2、双重检查锁定
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
3、静态内部类
这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的
机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装卸SingletonInstance类,从而完成Singleton的实例化。类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
优点:避免了线程不安全,延迟加载,效率高。
3、静态内部类
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
第3种相对与1、2种好一些,既实现了线程安全,又避免了同步带来的性能影响。
五.单例模式的优点
系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
六.单例模式的缺点
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。
七.单例模式的使用场景
• 需要频繁的进行创建和销毁的对象;
• 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
• 工具类对象;
• 频繁访问数据库或文件的对象。