6 implementations of the singleton mode (Singleton)

Source: Internet
Author: User

1.1.1 Summary

In our daily work we often need to keep a unique instance in the application, such as: IO processing, database operation, etc., because these objects occupy important system resources, so we must limit the creation of these instances or always use a common instance, this is what we are going to introduce today-- Singleton mode (Singleton).

High frequency of Use

Single-piece Mode (Singleton): guarantees that a class has only one instance and provides a global access point to access it.

1.1.2 Body

Figure 1 Single-case mode (SINGLETON) structure diagram

The singleton mode (Singleton) is the most antagonistic of several creation patterns, and its main feature is not to generate a new instance based on the user program invocation, but rather to control the instance uniqueness of a type by knowing that it contains only one of the roles, that is, Singleton, which has a private constructor , which ensures that users cannot instantiate it directly through new. In addition, the schema contains a static private member variable instance with the static Public method instance (). The Instance () method is responsible for verifying and instantiating itself, and then storing it in a static member variable to ensure that only one instance is created.

Figure 2 Single-case mode (Singleton) logic model

Next we'll show you how to implement the different singleton patterns (Singleton) in 6. These implementations all have the following common points:

    1. There is a private parameterless constructor, which prevents other classes from instantiating it, and the Singleton class should not be inherited, and if the Singleton class allows inheritance then each subclass can create an instance, which violates the original intention of the Singleton pattern "unique instance".
    2. The singleton class is defined as sealed, just as the class mentioned above should not be inherited, so it is safe to define the class as not allowed to derive, but it is not required to be defined.
    3. A static variable is used to hold a reference to a single instance.
    4. A public static method is used to obtain a reference to a single instance, and if the instance is null, one is created.

Version thread not secure

<summary>///A simple Singleton class implements.///</summary>public sealed class singleton{    private static Singleton _instance = null;    <summary>//    prevents a default instance of     the//<see cref= "Singleton"/> class from being Crea Ted.    </summary>    Private Singleton () {}///<summary>//    Gets the    instance.    </summary> public    static Singleton Instance    {        get {return _instance?? (_instance = new Singleton ()); }    }}

The above implementations are suitable for single-threaded environments where multiple instances of the Singleton class are likely to be obtained in a multithreaded environment. If you have two threads at a time to judge

(Null = = _singleton), and the result is true, then two threads will create instances of class Singleton, which violates the original intent of the singleton mode "unique instance".

Version second-thread security

<summary>///A Thread-safe Singleton class.///</summary>public sealed class singleton{    private static Singleton _instance = null;    private static readonly Object synobject = new Object ();    Singleton ()    {}//<summary>//    Gets the    instance.    </summary> public    static Singleton Instance    {        get        {            //Syn operation.            Lock (Synobject)            {                return _instance?? (_instance = new Singleton ());}}}}    

The way this is implemented is thread-safe, first we create a static read-only process helper, because lock ensures that when one thread is in the critical section of the code, another thread cannot enter the critical section (synchronous operation). If another thread attempts to enter the locked code, it waits until the object is freed. This ensures that multiple object instances are not created under multithreading. The only way to do this is to synchronize, which is the bottleneck that affects the performance of the system and adds additional overhead.

double-checked Locking

The problem with the implementation of thread safety mentioned earlier is to synchronize, so can we reduce the number of times we pass the operation? In fact, we just need to add the number of times to determine if the instance is null before synchronizing, which is the classic double-checked locking method.

<summary>///double-checked Locking implements a Thread-safe singleton class///</summary>public sealed C Lass singleton{    private static Singleton _instance = null;    Creates an Syn object.    private static readonly Object synobject = new Object ();    Singleton ()    {    } public    static Singleton Instance    {        get        {            //double-checked Locking            if (null = = _instance)            {                Lock (synobject)                {                    if (null = = _instance)                    {                        _instance = new Singleton ();            }}}            return _instance;}}    }

Before introducing the fourth implementation, let us first understand what is, when the field is marked as BeforeFieldInit type, that field initialization can occur at any time before any field is referenced. This sounds a bit awkward, let's take a concrete example.

<summary>///defines a test class.///</summary>class test{public    static string x = Echoandreturn ("in Type initializer ");    public static string Echoandreturn (string s)    {        Console.WriteLine (s);        return s;    }}

Above we define a class test that contains static fields and methods, but note that we do not define a static constructor.

Figure 3 IL code for the test class

Class test{public    static string x = Echoandreturn ("in type initializer");    Defines a parameterless constructor.    Static Test ()    {    } public    static string Echoandreturn (string s)    {        Console.WriteLine (s);        return s;    }}

Above we add a static constructor to the test class.

Figure 4 IL code for the test class

By the difference between the IL code of the test class above, we find that when the test class contains a static field and there is no static constructor defined, the class is marked as beforefieldinit.

Now one might ask, "What's the difference between being labeled beforefieldinit and unmarked?" OK now let's take a look at the difference between the following specific examples!

Class test{public    static string x = Echoandreturn ("in type initializer");    Static Test ()    {    } public    static string Echoandreturn (string s)    {        Console.WriteLine (s);        return s;    }} Class driver{public    static void Main ()    {        Console.WriteLine ("Starting Main");        Invoke a static method on Test        test.echoandreturn ("echo!");        Console.WriteLine ("After Echo");        Console.ReadLine ();        The output result:        //Starting Main        //in type initializer        //echo!        After Echo                }}

I believe everyone can get the answer, if you need to complete the initialization of the static member before calling the Echoandreturn () method, the final output is as follows:

Figure 5 Output results

We then add string y = Test.x in the main () method, as follows:

public static void Main () {    Console.WriteLine ("Starting Main");    Invoke a static method on Test    test.echoandreturn ("echo!");    Console.WriteLine ("After Echo");    Reference a static field in Test    string y = test.x;    Use the value just to avoid compiler cleverness    if (Y! = null)    {        Console.WriteLine ("After field access"); 
   }    Console.readkey ();    The output result:    //in type initializer    //starting Main    //echo!    After Echo    //after field access}

Figure 6 Output results

From the above output, you can find that the initialization of static field ran to the static method call before, Wo unimaginable ah!

Finally, we add a static constructor to the test class as follows:

Class test{public    static string x = Echoandreturn ("in type initializer");    Static Test ()    {    } public    static string Echoandreturn (string s)    {        Console.WriteLine (s);        return s;    }}

Figure 7 Output results

Theoretically, type initializer should occur in "echo!" After and "after Echo", but there are no unique results, only when the test class contains a static constructor, to ensure that the initialization of type initializer occurs in "echo!" And before "after Echo".

So to make sure that type initializer occurs when a field is referenced, we should add a static constructor to the class. Next, let's introduce the static mode of the singleton pattern.

Static initialization

public sealed class singleton{    private static readonly Singleton _instance = new Singleton ();    Explicit Static constructor to tell C # compiler    //not to mark type as beforefieldinit    static Singleton ()    {    }    <summary>//    prevents a default instance of     the//<see cref= "Singleton"/> class from being Crea Ted.    </summary>    Private Singleton () {}///<summary>//    Gets the    instance.    </summary> public    static Singleton Instance    {        get        {            return _instance;    }}

The above approach is simpler than previously described, but it is indeed a way of Singleton in C # implementations in a multithreaded environment. This static initialization is instantiated only when its own field is referenced.

Let's parse the static initialization through the IL code.

Figure 8 Static initialization of IL code

First, there is no beforefieldinit modifier, since we have added static constructors to initialize static fields when they are referenced, so even if many threads try to reference _instance, they need to wait for the static constructor to execute and put the static member _ Instance can be used after the instantiation is instantiated.

Deferred initialization

<summary>///delaies initialization.///</summary>public sealed class singleton{    private Singleton ()    {}//<summary>//    Gets the    instance.    </summary> public    static Singleton Instance {get {return nested._instance;}}    Private class Nested    {        //Explicit static constructor to tell C # compiler        //not to mark type as Beforefieldi NIT        static Nested ()        {        }        internal static readonly Singleton _instance = new Singleton ();}    }

Here we put the initialization work into a static member of the nested class, which allows for deferred initialization.

Lazy<t> type

<summary>///. NET 4 ' s lazy<t> type///</summary>public sealed class singleton{    private static R Eadonly lazy<singleton> Lazy =        new Lazy<singleton> (() = new Singleton ());    public static Singleton Instance {get {return lazy. Value; }}    private Singleton ()    {    }}

This approach is simple and performance-friendly, and also provides checks to see if an instance of the attribute isvaluecreated has been created.

Specific examples

Now let's implement a load balancer using singleton mode (Singleton), first we define a server class that contains the server name and IP address as follows:

<summary>///represents a server machine///</summary>class server{    //Gets or sets server name    PU Blic string Name {get; set;}    Gets or sets server IP address public    string IP {get; set;}}

Since the load balancer only provides an object instance for the server to use, we use singleton mode (Singleton) to implement the load balancer.

<summary>///the ' Singleton ' class///</summary>sealed class loadbalancer{private static ReadOnly Load    Balancer _instance = new LoadBalancer ();    Type-safe generic list of servers private list<server> _servers;    Private random _random = new Random ();  Static LoadBalancer () {}//Note:constructor is ' private ' private loadbalancer () {//Load list of  Available servers _servers = new List<server> {new server{Name = "Serveri", IP = "192.168.0.108"}, new server{name = "Serverii", IP = "192.168.0.109"}, new server{name = "S ERVERIII ", IP =" 192.168.0.110 "}, new server{Name =" Serveriv ", IP =" 192.168.0.111 "}, New Se    rver{Name = "Serverv", IP = "192.168.0.112"},};    }//<summary>//Gets The instance through static initialization.    </summary> public static LoadBalancer Instance {    get {return _instance;} }//simple, but effective load balancer public Server Nextserver {get {int r = _rando M.next (_servers.            Count);        return _SERVERS[R]; }    }}

Above the load Balancer class LoadBalancer We use static initialization to implement the Singleton mode (Singleton).

static void Main () {    LoadBalancer b1 = loadbalancer.instance;    B1. GetHashCode ();    LoadBalancer b2 = loadbalancer.instance;    LoadBalancer B3 = loadbalancer.instance;    LoadBalancer b4 = loadbalancer.instance;    Confirm These is the same instance    if (B1 = b2 && b2 = B3 && B3 = b4)    {        Console.writeli NE ("same instance\n");    }    Next, load balance requests for a server    loadbalancer balancer = loadbalancer.instance;    for (int i = 0; i < i++)    {        string serverName = balancer. Nextserver.name;        Console.WriteLine ("Dispatch Request to:" + serverName);    }    Console.readkey ();}

Figure 9 LoadBalancer output Results

1.1.3 Summary

Advantages of Singleton mode:

The singleton mode (Singleton) controls the number of instance objects, ensuring the uniqueness of the Access object.

    1. Instance control: Singleton mode prevents other objects from instantiating themselves, ensuring that all objects have access to an instance.
    2. Scalability: Because the class itself controls the instantiation process, the class has the appropriate scalability to change the instantiation process.

Disadvantages of the Singleton pattern:

    1. System overhead. Although this overhead may seem small, there is a check for the existence of an instance every time the instance of this class is referenced. This problem can be solved by static instance.
    2. Development confusion. When using an object in a singleton mode (especially in a class library), the developer must remember that the object cannot be instantiated with the new keyword. Because developers do not see the source code in the class library, they are surprised when they find that they cannot instantiate a class.
    3. The object life cycle. The singleton mode does not propose object destruction. In the development language that provides memory management (for example, based on the. NETFramework language), only the Singleton schema object itself can destroy an object instance, because only it has a reference to the instance. In a variety of development languages, such as C + +, other classes can destroy object instances, but doing so will cause pointers within the singleton class to point to unknown.

Applicability of single case

There is a requirement for using the singleton mode: Singleton mode should be used when a system requires only one instance of a class. Conversely, if a class can have several instances coexisting, do not use singleton mode.

Do not use singleton mode to access global variables. This violates the intent of the singleton pattern and is best placed in the static member of the corresponding class.

Do not make the database connection a singleton, because a system may have multiple connections to the database, and in the case of a connection pool, the connection should be released as promptly as possible. Singleton mode because of the use of static member storage class instances, it can cause resources can not be released in time, causing problems.

6 implementations of the singleton mode (Singleton)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.