📜  演示单例类嵌套初始化的Java程序

📅  最后修改于: 2022-05-13 01:54:38.437000             🧑  作者: Mango

演示单例类嵌套初始化的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!

嵌套初始化的优点:

  • 延迟加载
  • 线程安全

延迟加载

  1. 延迟加载只是将对象创建推迟到实际需要时。
  2. 由于减少了程序启动期间的开销,因此可以提高性能。
  3. 在我们的例子中,直到第一次调用 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