一种 单例类 只能生成一个实例。每个 Singleton 类都有一个返回其对象的 getInstance 方法。第一次调用 getInstance 方法时,会生成、存储并返回该类的对象。在后续调用 getInstance 时,将返回先前生成的相同对象。

嵌套初始化 可用于创建单例类。
在下面的实现中,我们使用嵌套初始化创建一个单例类。进行以下观察:

  • 该类默认的无参数构造函数是私有的,以防止其他类直接访问它并创建 Singleton 对象。
  • Singleton 类有一个静态公共 getInstance 方法,其返回类型为 Singleton。其他类将使用它来获取 Singleton 对象。
  • Singleton 类中有一个 嵌套 类。该嵌套类有一个 Instance 变量,用于存储 Singleton 类的对象。
  • getInstance 方法从 Instance 变量获取值并将其返回到调用站点。

使用嵌套初始化创建单例类的演示

Java
//演示Singleton类的Java程序
// 使用嵌套初始化
​
类单例{
​
// 一个成员变量
字符串 str = "GFG!";
​
// 嵌套类只有 1 个角色,即创建
// 单例对象并将其存储在实例变量中
私有静态类嵌套{
静态单例实例 = new Singleton();
}
​
// getInstance()方法返回的对象// Singleton 类存储在 Instance 变量中
公共静态单例 getInstance()
{
返回嵌套实例;
}

// 无参构造函数必须设为私有
// 这强制其他类使用 getInstance() 方法
// 为了获取Singleton类的实例

私有单例()
{
System.out.println("对象已完成");
}
}

公共类主要{

公共静态无效主(字符串[]参数)
{
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();

// 更改 obj1.str 并输出 obj2.str
obj1.str = "geeksforgeeks!";

System.out.println(obj2.str);
}
}


Java
//演示线程安全需求的Java程序

类单例1 {
静态 Singleton1 对象;

私有 Singleton1()
{
System.out.println("对象已完成");
}

// 该方法返回obj// 如果两个线程同时进入getInstance
// 然后两者都将 obj 视为 null,因此有 2 个对象
// Singleton1 被创建,这违背了目的
// 单例类
静态 Singleton1 getInstance()
{
如果(对象==空)
obj = new Singleton1();

返回对象;
}
}

公共类主要{
公共静态无效主(字符串[]参数)
{

// 线程1将调用getInstance
线程 t1 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton1 a = Singleton1.getInstance();
}
});

// 线程2也会调用getInstance
线程 t2 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton1 b = Singleton1.getInstance();
}
});

// 启动两个线程
t1.start();
t2.start();
}}


Java
//演示线程安全的Java程序
// 在嵌套初始化中

类单例{

私有静态类嵌套{
静态单例实例 = new Singleton();
}

// 该方法返回Object,但不创建它
// 对象是在嵌套类初始化时创建的
// 只发生一次。
公共静态单例 getInstance()
{
返回嵌套实例;
}

私有单例()
{
System.out.println("对象已完成");
}
}

公共类 SingletonDemo {
公共静态无效主(字符串[]参数)
{

// 线程1将调用getInstance
线程 t1 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton a = Singleton.getInstance();
}
});

// 线程2也会调用getInstance
线程 t2 = 新线程(新 Runnable() {
公共无效运行()
{Singleton b = Singleton.getInstance();

});
​
// 启动两个线程
t1.start();
t2.start();
}
}


输出
对象制作
极客归极客!

嵌套初始化的优点:

  • 延迟加载
  • 线程安全

延迟加载

  1. 延迟加载只是将对象创建推迟到实际需要时为止。
  2. 由于程序启动期间的开销减少而提高了性能。
  3. 在我们的例子中,直到第一次调用 getInstance 方法时才创建 Singleton 类的对象。

线程安全: 线程安全至关重要,否则多线程程序可能会产生意想不到的随机结果。

  • Singleton 类的非线程安全实现

Java

// 用于演示线程安全需求的 Java 程序
​
类单例1 {
静态 Singleton1 对象;
​
私有 Singleton1()
{
System.out.println("对象已完成");
}
​
// 该方法返回obj
// 如果两个线程同时进入getInstance
// 然后两者都将 obj 视为 null,因此有 2 个对象
// Singleton1 被创建,这违背了目的
// 单例类
静态 Singleton1 getInstance()
{
如果(对象==空)obj = new Singleton1();

返回对象;
}
}

公共类主要{
公共静态无效主(字符串[]参数)
{

// 线程1将调用getInstance
线程 t1 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton1 a = Singleton1.getInstance();
}
});

// 线程2也会调用getInstance
线程 t2 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton1 b = Singleton1.getInstance();
}
});

// 启动两个线程
t1.start();
t2.start();
}
}
输出
制作的物品
物体制作
  • 初始化初始化线程安全的,这是因为与初始化中的上述实现不同,getInstance方法不创建对象,它只是返回它。该对象是在初始化初始化套类时创建的,并且仅在第一次调用 getInstance 方法时发生一次。

单例类的线程安全实现

Java

//演示线程安全的Java程序
// 在嵌套初始化中

类单例{
私有静态类嵌套{
静态单例实例 = new Singleton();
}

// 该方法返回Object,但不创建它
// 对象是在嵌套类初始化时创建的
// 只发生一次。
公共静态单例 getInstance()
{
返回嵌套实例;
}

私有单例()
{
System.out.println("对象已完成");
}
}

公共类 SingletonDemo {
公共静态无效主(字符串[]参数)
{

// 线程1将调用getInstance
线程 t1 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton a = Singleton.getInstance();
}
});

// 线程2也会调用getInstance
线程 t2 = 新线程(新 Runnable() {
公共无效运行()
{
Singleton b = Singleton.getInstance();
}
});
// 启动两个线程
t1.start();
t2.start();
}
}
输出
制作的物品