一种 单例类 只能生成一个实例。每个 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();
}
}
输出
对象制作
极客归极客!
嵌套初始化的优点:
- 延迟加载
- 线程安全
延迟加载 :
- 延迟加载只是将对象创建推迟到实际需要时为止。
- 由于程序启动期间的开销减少而提高了性能。
- 在我们的例子中,直到第一次调用 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();
}
}
输出
制作的物品
注意:在上面的实现中我们没有使用synchronized关键字就实现了线程安全。这是一个优点,因为众所周知,synchronized 关键字会显着影响性能。
编程需要懂一点英语