专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 Java学习 Java单例设计模式示例

Java单例设计模式示例

更新时间:2022-03-23 11:42:35 来源:动力节点 浏览1093次

在本文中,我们将了解如何创建单例类。阅读本文后,您将能够根据您的使用、简单性和消除瓶颈来创建您的单例类。

在 Java 中有很多方法可以做到这一点。所有这些方式在模式的实现上都有所不同,但最终,它们都实现了单个实例的相同最终结果。

1.急切初始化:

这是创建单例类的最简单方法。在这种情况下,类的对象是在JVM加载到内存时创建的。这是通过直接为引用分配一个实例来完成的。

当程序总是使用这个类的实例,或者创建实例的资源和时间成本不是太大时,可以使用它。

// Java code to create singleton class by
// Eager Initialization
public class GFG
{
// public instance initialized when loading the class
private static final GFG instance = new GFG();
private GFG()
{
	// private constructor
}
public static GFG getInstance(){
		return instance;
	}
}

优点:

实现起来非常简单。

可能导致资源浪费。因为类的实例总是被创建,无论它是否需要。

如果不需要,CPU 时间也会浪费在创建实例上。

异常处理是不可能的。

2.使用静态块:

这也是 Eager 初始化的子部分。唯一的区别是对象是在静态块中创建的,因此我们可以访问它的创建,例如异常处理。以这种方式,对象也是在类加载时创建的。

当使用急切初始化创建对象时有可能出现异常时,可以使用它。

// Java code to create singleton class
// Using Static block
public class GFG
{
// public instance
public static GFG instance;
private GFG()
{
	// private constructor
}
static
{
	// static block to initialize instance
	instance = new GFG();
}
}

优点:

实现起来非常简单。

无需实现 getInstance() 方法。可以直接访问实例。

异常可以在静态块中处理。

可能导致资源浪费。因为类的实例总是被创建,无论它是否需要。

如果不需要,CPU 时间也会浪费在创建实例上。

3.延迟初始化:

在此方法中,仅在需要时才创建对象。这可以防止资源浪费。需要返回实例的 getInstance() 方法的实现。有一个空检查,如果没有创建对象然后创建,否则返回以前创建的。为了确保该类不能以任何其他方式实例化,构造函数是最终的。由于对象是在方法中创建的,因此它确保除非需要,否则不会创建对象。实例是私有的,因此没有人可以直接访问它。

它可以在单线程环境中使用,因为多个线程可以破坏单例属性,因为它们可以同时访问 get 实例方法并创建多个对象。

//Java Code to create singleton class
// With Lazy initialization
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
	// private constructor
}
//method to return instance of class
public static GFG getInstance()
{
	if (instance == null)
	{
	// if instance is null, initialize
	instance = new GFG();
	}
	return instance;
}
}

优点:

只有在需要时才创建对象。它可以克服资源消耗和 CPU 时间的浪费。

在方法中也可以进行异常处理。

每次都必须检查 null 的条件。

无法直接访问实例。

在多线程环境中,它可能会破坏单例属性。

4.线程安全单例:

创建了一个线程安全的单例,这样即使在多线程环境中也可以保持单例属性。为了使单例类线程安全,getInstance() 方法是同步的,因此多个线程不能同时访问它。

// Java program to create Thread Safe
// Singleton class
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
	// private constructor
}
//synchronized method to control simultaneous access
synchronized public static GFG getInstance()
{
	if (instance == null)
	{
	// if instance is null, initialize
	instance = new GFG();
	}
	return instance;
}
}

优点:

延迟初始化是可能的。

它也是线程安全的。

getInstance() 方法是同步的,因此会导致性能下降,因为多个线程无法同时访问它。

5.带有双重检查锁定的延迟初始化:

在这种机制中,我们克服了同步代码的开销问题。在此方法中,getInstance 不同步,但创建实例的块是同步的,因此必须等待最少数量的线程,这只是第一次。

// Java code to explain double check locking
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
	// private constructor
}
public static GFG getInstance()
{
	if (instance == null)
	{
	//synchronized block to remove overhead
	synchronized (GFG.class)
	{
		if(instance==null)
		{
		// if instance is null, initialize
		instance = new GFG();
		}	
	}
	}
	return instance;
}
}

优点:

延迟初始化是可能的。

它也是线程安全的。

由于 synchronized 关键字,性能开销得到了降低。

第一次,它会影响性能。

6.Bill Pugh Singleton 实现:

在Java5之前,内存模型有很多问题,以上方法在多线程环境中的某些场景下会导致失败。所以,Bill Pugh 提出了一个内部静态类的概念,用于单例。

// Java code for Bill Pugh Singleton Implementation
public class GFG
{
private GFG()
{
	// private constructor
}
// Inner class to provide instance of class
private static class BillPughSingleton
{
	private static final GFG INSTANCE = new GFG();
}
public static GFG getInstance()
{
	return BillPughSingleton.INSTANCE;
}
}

加载单例类时,不会加载内部类,因此在加载类时不会创建对象。只有在调用 getInstance() 方法时才会创建内部类。所以它可能看起来像急切的初始化,但它是延迟初始化。

这是最广泛Java单例设计模式使用的方法,因为它不使用同步。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>