演示单例类嵌套初始化的Java程序
一种 单例类只能生成一个实例。每个 Singleton 类都有一个返回其对象的 getInstance 方法。首次调用 getInstance 方法时,会生成、存储该类的一个对象,然后返回。在对 getInstance 的后续调用中,将返回之前生成的相同对象。
嵌套初始化可用于制作单例类。
在下面的实现中,我们使用嵌套初始化创建了一个单例类。进行以下观察:
- 该类的默认无参数构造函数是私有的,以防止其他类直接访问它并创建 Singleton 的对象。
- Singleton 类有一个静态公共 getInstance 方法,以 Singleton 作为返回类型。这将被其他类用来获取 Singleton 的对象。
- Singleton 类中有一个嵌套类。这个嵌套类有一个 Instance 变量,用于存储 Singleton 类的对象。
- getInstance 方法从该 Instance 变量中获取值并将其返回到调用站点。
使用嵌套初始化创建单例类的演示
Java
// Java Program to demonstrate Singleton Class
// using Nested Initialization
class Singleton {
// a member variable
String str = "GFG!";
// Nested class has just 1 role i.e.creation of the
// Singleton object and storing it in Instance variable
private static class Nested {
static Singleton Instance = new Singleton();
}
// The getInstance() method returns the object of
// Singleton class stored in Instance variable
public static Singleton getInstance()
{
return Nested.Instance;
}
// no-argument constructor has to be made private
// this forces other classes to use getInstance() method
// in order to obtain the instance of Singleton class
private Singleton()
{
System.out.println("Object made");
}
}
public class Main {
public static void main(String[] args)
{
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
// make changes to obj1.str and output obj2.str
obj1.str = "geeksforgeeks!";
System.out.println(obj2.str);
}
}
Java
// Java Program to demonstrate need of Thread-Safety
class Singleton1 {
static Singleton1 obj;
private Singleton1()
{
System.out.println("Object made");
}
// This method returns obj
// If both the threads enter getInstance simultaneously
// then both see obj as null, hence 2 objects of
// Singleton1 are created this defeats purpose of
// Singleton class
static Singleton1 getInstance()
{
if (obj == null)
obj = new Singleton1();
return obj;
}
}
public class Main {
public static void main(String[] args)
{
// Thread 1 will call getInstance
Thread t1 = new Thread(new Runnable() {
public void run()
{
Singleton1 a = Singleton1.getInstance();
}
});
// Thread 2 will also call getInstance
Thread t2 = new Thread(new Runnable() {
public void run()
{
Singleton1 b = Singleton1.getInstance();
}
});
// Start both the Threads
t1.start();
t2.start();
}
}
Java
// Java Program to demonstrate Thread-Safety
// in NestedInitialization
class Singleton {
private static class Nested {
static Singleton Instance = new Singleton();
}
// This method returns Object, does not create it
// Object is created on initialization of Nested class
// which happens only once.
public static Singleton getInstance()
{
return Nested.Instance;
}
private Singleton()
{
System.out.println("Object made");
}
}
public class SingletonDemo {
public static void main(String[] args)
{
// Thread 1 will call getInstance
Thread t1 = new Thread(new Runnable() {
public void run()
{
Singleton a = Singleton.getInstance();
}
});
// Thread 2 will also call getInstance
Thread t2 = new Thread(new Runnable() {
public void run()
{
Singleton b = Singleton.getInstance();
}
});
// Start both the Threads
t1.start();
t2.start();
}
}
输出
Object made
geeksforgeeks!
嵌套初始化的优点:
- 延迟加载
- 线程安全
延迟加载:
- 延迟加载只是将对象创建推迟到实际需要时。
- 由于减少了程序启动期间的开销,因此可以提高性能。
- 在我们的例子中,直到第一次调用 getInstance 方法时才会创建 Singleton 类的对象。
线程安全: 线程安全是必不可少的,否则多线程程序可能会产生意外的随机结果。
- Singleton 类的非线程安全实现
Java
// Java Program to demonstrate need of Thread-Safety
class Singleton1 {
static Singleton1 obj;
private Singleton1()
{
System.out.println("Object made");
}
// This method returns obj
// If both the threads enter getInstance simultaneously
// then both see obj as null, hence 2 objects of
// Singleton1 are created this defeats purpose of
// Singleton class
static Singleton1 getInstance()
{
if (obj == null)
obj = new Singleton1();
return obj;
}
}
public class Main {
public static void main(String[] args)
{
// Thread 1 will call getInstance
Thread t1 = new Thread(new Runnable() {
public void run()
{
Singleton1 a = Singleton1.getInstance();
}
});
// Thread 2 will also call getInstance
Thread t2 = new Thread(new Runnable() {
public void run()
{
Singleton1 b = Singleton1.getInstance();
}
});
// Start both the Threads
t1.start();
t2.start();
}
}
输出
Object made
Object made
- 嵌套初始化是线程安全的,这是因为与嵌套初始化中的上述实现不同,getInstance 方法不创建对象,它只是返回它。该对象是在初始化嵌套类时创建的,并且仅在第一次调用 getInstance 方法时发生一次。
Singleton 类的线程安全实现
Java
// Java Program to demonstrate Thread-Safety
// in NestedInitialization
class Singleton {
private static class Nested {
static Singleton Instance = new Singleton();
}
// This method returns Object, does not create it
// Object is created on initialization of Nested class
// which happens only once.
public static Singleton getInstance()
{
return Nested.Instance;
}
private Singleton()
{
System.out.println("Object made");
}
}
public class SingletonDemo {
public static void main(String[] args)
{
// Thread 1 will call getInstance
Thread t1 = new Thread(new Runnable() {
public void run()
{
Singleton a = Singleton.getInstance();
}
});
// Thread 2 will also call getInstance
Thread t2 = new Thread(new Runnable() {
public void run()
{
Singleton b = Singleton.getInstance();
}
});
// Start both the Threads
t1.start();
t2.start();
}
}
输出
Object made
Note: In the above implementation we have achieved thread-safety without using the synchronized keyword. This is a plus point since the synchronized keyword is known to affect performance noticeably.