Singleton design pattern in C #

Singleton pattern 

   Singleton (translated as a single piece or single-state) mode is relatively simple design mode and common mode.

   Sometimes the entire application will require a class has one and only one instance, this time using the Singleton pattern can be designed. Singleton pattern with classes designed to ensure not only that only one instance in the application, but also provides a method of non-global access global variable, called global access point, so that for the pure object-oriented languages have no concept of global variables is very convenient, such as C #.

   Examples of a counter used herein to describe how to use the Singleton Pattern in C #: count value of variable member designed as a private class counter, which is read and write operations of four different threads, in order to ensure the accuracy of counting, the entire among the application class instance counter inevitable requirement is unique.

Singleton implementation 

   first two methods See Singleton standard textbooks implemented embodiment, the following C # class using a pseudo-code:

   Method a:

using System;
namespace csPattern.Singleton
{
public class Singleton
{
static Singleton uniSingleton = new Singleton();
private Singleton() {}
static public Singleton instance()
{
return uniSingleton;
}
}
}


   Method Two:

using System;
namespace csPattern.Singleton
{
public class Singleton
{
static Singleton uniSingleton;
private Singleton() {}
static public Singleton instance()
{
if (null == uniSingleton)
{
uniSingleton = new Singleton _lazy();
}
return uniSingleton;
}
}
}


   Implements the Singleton pattern of two techniques: First, use a static member variables to store instances "global" to ensure uniqueness, use a static member method instance () instead of new keywords to get the class instance, reach globally visible effect. Second, the constructor is set to be private, if you use the keywords to create a new instance of the class, the compiler error, in case the programming time clerical error.

   Examples of the above examples initialization method known as two way lazy initialization, create a class is only required when the first instance of a class and method of use do not matter have always been compared to method two more to conserve system resources. But the second method sometimes multiple instances of the phenomenon will occur in multi-threaded applications.
   The assumption here there are two threads: the main thread and thread 1, when the instance of the class is created may encounter some reason blocked a period of time (such as network speed or the need to wait for the release of some of the resources being used), then run as follows:

   the main thread to call first instance () attempts to get an instance of the class, instance () method to determine the class members do not create a unique instance, he began to create an instance. Due to a number of factors, the main thread can not create a successful immediately, but need to wait for some time. Thread 1 is also at this time to call the instance () trying to get instances of the class, because the instance has not yet been successfully created main thread, the thread 1 began to create a new instance. The result is to create two threads are two examples for class counter, the counted value will lead is reset, contrary to the original intention Singleton. The solution to this problem is to synchronize.

   See counter herein achieve the following example:

   using a method:

the System the using;
the using the System.Threading;
namespace csPattern.Singleton
{
public class Counter
{
static uniCounter = new new Counter Counter (); // store unique instance.
private int totNum = 0; // count value is stored.
Counter Private ()
{
the Thread.Sleep (100); // assumed here that the delay because of some factors 100 milliseconds.
// In the case of non-lazy initialization will not affect the count. .
}
Static public instance Counter ()
{
return uniCounter;
}
public void Inc is an () {totNum ++;} // count is incremented.
public int GetCounter () {return totNum ;} // get the current count value.
}
}


   The following is a call to the Counter class clients, where we defined four threads simultaneously using a counter for each thread uses 4 times to obtain the correct result should be 16:

using System;
using System.IO;
using System.Threading;
namespace csPattern.Singleton.MutileThread
{
public class MutileClient
{
public MutileClient() {}
public void DoSomeWork()
{
Counter myCounter = Counter.instance(); //方法一
//Counter_lazy myCounter = Counter_lazy.instance(); //方法二
for (int i = 1; i < 5; i++)
{
myCounter.Inc();
Console.WriteLine("线程{0}报告: 当前counter为: {1}", Thread.CurrentThread.Name.ToString(), myCounter.GetCounter().ToString());
}
}
public void ClientMain()
{
Thread thread0 = Thread.CurrentThread;
thread0.Name = "Thread 0";
Thread thread1 =new Thread(new ThreadStart(this.DoSomeWork));
thread1.Name = "Thread 1";
Thread thread2 =new Thread(new ThreadStart(this.DoSomeWork));
thread2.Name = "Thread 2";
Thread thread3 =new Thread(new ThreadStart(this.DoSomeWork));
thread3.Name = "Thread 3";
thread1.Start();
thread2.Start();
thread3.Start();
DoSomeWork(); //线程0也只执行和其他线程相同的工作。
}
}
}


   以下为Main函数,本程序的测试入口:

using System;
namespace csPattern.Singleton
{
public class RunMain
{
public RunMain() {}
static public void Main(string[] args)
{
MutileThread.MutileClient myClient = new MutileThread.MutileClient();
myClient.ClientMain();
System.Console.ReadLine();
}
}
}


   执行结果如下:

   线程Thread 1报告: 当前counter为: 2
   线程Thread 1报告: 当前counter为: 4
   线程Thread 1报告: 当前counter为: 5
   线程Thread 1报告: 当前counter为: 6
   线程Thread 3报告: 当前counter为: 7
   线程Thread 3报告: 当前counter为: 8
   线程Thread 3报告: 当前counter为: 9
   线程Thread 3报告: 当前counter为: 10
   线程Thread 0报告: 当前counter为: 1
   线程Thread 0报告: 当前counter为: 11
   线程Thread 0报告: 当前counter为: 12
   线程Thread 0报告: 当前counter为: 13
   线程Thread 2报告: 当前counter为: 3
   线程Thread 2报告: 当前counter为: 14
   线程Thread 2报告: 当前counter为: 15
   线程Thread 2报告: 当前counter为: 16

   由于系统线程调度的不同,每次的执行结果也不同,但是最终结果一定是16。

   方法一中由于实例一开始就被创建,所以instance()方法无需再去判断是否已经存在唯一的实例,而返回该实例,所以不会出现计数器类多次实例化的问题。
   使用方法二:

using System;
using System.Threading;
using System.Runtime.CompilerServices;
namespace csPattern.Singleton
{
public class Counter_lazy
{
static Counter_lazy uniCounter;
private int totNum = 0;
private Counter_lazy()
{
Thread.Sleep(100); //假设多线程的时候因某种原因阻塞100毫秒
}
[MethodImpl(MethodImplOptions.Synchronized)] //方法的同步属性
static public Counter_lazy instance()
{
if (null == uniCounter)
{
uniCounter = new Counter_lazy();
}
return uniCounter;
}
public void Inc() { totNum ++;}
public int GetCounter() { return totNum;}
}
}


   不知道大家有没有注意到instance()方法上方的[MethodImpl(MethodImplOptions.Synchronized)] 语句,他就是同步的要点,他指定了instance()方法同时只能被一个线程使用,这样就避免了线程0调用instance()创建完成实例前线程1就来调用instance()试图获得该实例。

   根据MSDN的提示,也可以使用lock关键字进行线程的加锁,代码如下:

using System;
using System.Threading;
namespace csPattern.Singleton
{
public class Counter_lazy
{
static Counter_lazy uniCounter;
static object myObject = new object();
private int totNum = 0;
private Counter_lazy()
{
Thread.Sleep(100); //假设多线程的时候因某种原因阻塞100毫秒
}
static public Counter_lazy instance()
{
lock(myObject)
{
if (null == uniCounter)
{
uniCounter = new Counter_lazy();
}
return uniCounter;
}
}
public void Inc() { totNum ++;}
public int GetCounter() { return totNum;}
}
}


   lock()是对一个对象加互斥锁,只允许一个线程访问其后大括号中语句块,直到该语句块的代码执行完才解锁,解锁后才允许其他的线程执行其语句块。

   还可以使用Mutex类进行同步,定义private static Mutex mut = new Mutex();后,修改instance()如下,同样可以得到正确的结果:

static public Counter_lazy instance()
{
mut.WaitOne();
if (null == uniCounter)
{
uniCounter = new Counter_lazy();
}
mut.ReleaseMutex();
return uniCounter;
}


   注意的是,本例中使用方法二要更改方法一的客户程序,去掉Counter_lazy.intance()的注释,并将Counter.intance()注释。

   singleton模式还可以拓展,只要稍加修改,就可以限制在某个应用中只能允许m个实例存在,而且为m个实例提供全局透明的访问方法。

 深圳代孕电13802269370  代孕微13802269370  北京代孕微13802269370

Guess you like

Origin www.cnblogs.com/bbc2020/p/12457297.html