Design Mode: Singleton)
Wu jian2013-06-05
OriginalArticle, Reprint must indicate the source: http://www.cnblogs.com/wu-jian
Preface
The Singleton mode is one of the first design patterns that we know and often use. It was a long time ago that we wanted to write it down, but it was delayed due to insufficient preparation for some details. This article uses examples andCodeThe requirements, principles, and implementation of the singleton mode are analyzed, and the single-case mode and Performance Optimization in B/S development are discussed. I also hope to help my friends who learn the design model. At the same time, my personal abilities are limited. please correct me if there are any deficiencies in this article.
Why Singleton mode?
First, let's take a look at the definition of Singleton mode: Singleton mode is an object creation mode, which has the following features:
1. Ensure that one class has only one instance
2. You must create your own unique instance.
3. Provide global access points for a unique instance
The Singleton mode has many application scenarios, such as printers.ProgramA simple explanation of the problem: if there is a printer, we have written a print program. If this printer can be used everywhere for new (), a new is used, and B New is used, before printing a, B starts printing again. Therefore, the printer program must use the singleton mode, that is, only one object can communicate with the printer. If both A and B are printed, queue in the singleton object.
To use the simplest example to understand a Singleton, I think Obama is more representative: The Singleton model is like the president of the United States. The President of the United States can only have one. If there are multiple? It is estimated that the Chinese people, especially the North Korean people, will be happy.
Implementation of the singleton Mode
The Singleton mode can be implemented in two ways: ELE. Me and lazy. The Code is as follows:
// Ele. Me Public Sealed Class Hungryman { // Class instantiation during loading Private Static Hungryman minstance = New Hungryman (); // Private Constructor Private Hungryman (){} // Provides global access points in simple factory Mode Public Static Hungryman instance { Get { Return Minstance ;}}}
Ele. Me is the easiest way to implement singleton. It is also a typical space change time. When a class is loaded, an instance is created, regardless of whether the instance needs to be used or not. When the instance is used in the future, no judgment is made, saving the running time but occupying the space. Some frequently used objects are suitable for the hungry Chinese.
Perfect hunger
If you are not perfectionist, you can ignore this section because the code in this section cannot improve performance in most cases.
When using the hunger mode, C # does not guarantee the creation time of the instance, as follows:
Private StaticHungryman minstance =NewHungryman ();
Static fields may be assigned values when the class is loaded or before being called. In short, we cannot determine when to create a class instance. As a result, the perfectionist suggested that the uncertainty caused by this CLR mechanism will lead to performance loss. Can minstance be initialized instantly before it is called? This can save memory overhead for a period of time. So the optimized version of ELE. Me is as follows:
// Perfect hunger Public Sealed Class Perfecthungryman { Private Static Readonly Perfecthungryman minstance = New Perfecthungryman (); Private Perfecthungryman (){} // Implement delayed initialization through static Constructor Static Perfecthungryman (){} Public Static Perfecthungryman instance { Get { Return Minstance ;}}}
For example, the comments in the code implement class delay initialization through the static Constructor (that is, initialization before the call ). Comparing the intermediate code generated by the two classes, we can see that there is only one difference: perfecthungryman has one less feature than hungryman: beforefieldinit, that is, the static constructor has restrained the beforefieldinit feature, this feature affects class initialization. Obtain Il, as shown in:
Classes that contain beforefieldinit will be initialized by the CLR when appropriate; classes that do not contain beforefieldinit will be forcibly initialized before the call. As described at the beginning of this section, in most cases, the initialization of the beforefieldinit delay class can not improve the performance, or the performance will be slightly improved.
So unless in special cases, we don't have to pick up sesame seeds and drop the watermelon.
Implementation of the singleton mode (non-thread security)
The lazy is created only when necessary, as shown in the following code:
// Lazy Public Sealed Class Lazyman { Private Static Lazyman minstance = Null ; Private Lazyman (){} // Instantiate as needed Public Static Lazyman instance { Get { If (Minstance = Null ) Minstance = New Lazyman (); Return Minstance ;}}}
But there is a problem in the code, that is, when two or more requests are called at the same time in a multi-threaded environment, multiple objects will be created, which violates the basic principles of Singleton.
Loose in thread security
// Loose in thread security Public Sealed Class Multilazyman { Private Static Multilazyman minstance = Null ; Private Static Readonly Object Synclock = New Object (); Private Multilazyman (){} // Instantiate as needed Public Static Multilazyman instance { Get { // Ensure single-thread access Lock (Synclock ){ If (Minstance =Null ) Minstance = New Multilazyman (); Return Minstance ;}}}}
The implementation of the above Code is thread-safe. First, a static read-only process auxiliary object is created. Lock ensures that when a thread is located in the critical section of the Code, another thread cannot enter the critical section (synchronous operation ). If other threads attempt to enter the locked code, they will wait until the object is released. This ensures that multiple object instances are not created under multiple threads.
This implementation ensures the uniqueness of instances in a multi-threaded environment. However, from the code, we can find that each thread occupies lock. If a web program has 100 requests at the same time, it will lock 100 times, and there will always be queues. In terms of performance, this method has low efficiency and high performance overhead.
Perfect lazy
In a multi-threaded environment, we only need to use lock when creating an instance for the first time to ensure that the instance is unique. After the instance is created, it can be shared by everyone. Add a line of small judgment, as shown in the following code:
// Perfect lazy Public Sealed Class Perfectlazyman { // The volatile keyword indicates that a field can be modified by multiple concurrent threads. // Fields declared as volatile are not restricted by Compiler Optimization (assuming that they are accessed by a single thread. // This ensures that the field displays the latest value at any time. Private Static Volatile Perfectlazyman minstance =Null ; Private Static Readonly Object Synclock = New Object (); Private Perfectlazyman (){} Public Static Perfectlazyman instance { Get { // The lock is performed only when the instance is created for the first time. If (Minstance = Null ){ // Ensure single-thread access Lock (Synclock ){ If (Minstance = Null ) Minstance = New Perfectlazyman ();}} Return Minstance ;}}}
OK. It's a perfect lazy to be judged by one hand.
If you look up the information, this manual judgment actually has a seemingly profound terminology: Double Check Idiom)
The term is changed from C to Java and then from Java to C #. I am lucky to have read the relevant details in macro's "Java and patterns". By the way, I also recommend this book. Although it is a bit thick, it is still well written. If the author has less dogmatism, this book should be a model for Chinese design patterns.
Lazy <t>
// Lazy <t> Public Sealed Class Genericlazyman { Private Static Readonly Lazy <genericlazyman> minstance = New Lazy <genericlazyman> () => New Genericlazyman ()); Private Genericlazyman (){} Public Static Genericlazyman instance { Get { Return Minstance. Value ;}}}
Lazy <t> is an encapsulation provided by. NET Framework 4.x for large object delay loading. It provides a series of convenient functions and thread security, which is not described here.
Lazy <t> reference: http://msdn.microsoft.com/en-us/library/dd997286 (vs.100). aspx
Singleton mode and Performance
In B/S development, I think everyone has written the following code:
Protected VoidPage_load (ObjectSender, eventargs e) {businessobject=NewSomewhere. businessobject (); businessobject. dosomething ();}
Create a Business Object and call the object method to complete some operations.
Because. net, Java, and other advanced languages have built-in garbage collection mechanisms. We can take care of the concurrent memory overhead by GC (garbage collection, garbage collection, therefore, the above Code won't be faulty in most cases, so that we gradually forget concurrency, memory, and performance.
B/S development is intended for multiple users to process concurrent requests. The new object in page_load is used for each request. When 1000 people visit a page at the same time, we actually put 1000 new objects in the memory. If it happens that this object has more than 10 MB, that means the memory overhead will be greater than 10 Gb. This is a terrible number, but we don't often encounter 1000 concurrent and 10 m objects. Of course, we also have garbage collection to escort.
Below I have simulated an object of around 100 MB, with concurrency. Let's look at the following CPU and memory curves:
First, the CPU usage soared, and then the memory overhead experienced regular peaks and valleys. Obviously, each peak represents the beginning of garbage collection, and each bottom represents the end of garbage collection. Although garbage collection brings us convenience, it is also known to all for its performance loss. Attached to this testSource code:
Namespace WUJian. designmodel. Singleton { Public Class Testobject { // Load a m Image Public Testobject (){ This . Mdata = system. Drawing. image. fromfile (httpruntime. appdomainapppath + @" App_data \ 1500k.jpg " );} Private System. Drawing. Image mdata; Public System. Drawing. Image Data { Get {Return This . Mdata ;} Set { This . Mdata = Value ;}}} Public Partial Class Staticdemo: system. Web. UI. Page { Protected Void Page_load ( Object Sender, eventargs e) {testobject OBJ = New Testobject (); response. Write ( " Image Width is " + Obj. Data. Width + " Px " );}}}
Next let's take a look at the single-instance mode of the same 100 m object, concurrency:
The memory overhead is a straight line with no peaks and valleys, no garbage collection, and almost no impact on the number of concurrency. 100 of concurrency and 1000 of concurrency are identical in the memory overhead. Paste the code changes section:
Public Partial Class Staticdemo: system. Web. UI. Page { // Singleton Mode Private Static Readonly Testobject OBJ = New Testobject (); Protected Void Page_load ( Object Sender, eventargs e) {response. Write ( " Image Width is " + Obj. Data. Width + " Px " );}}
The example is very simple, and its purpose is only to arouse some thinking. Do you care about the memory overhead of reusable objects? Have you become a prisoner of garbage collection?
Download demo
Demo environment: Visual Studio 2012,. NET Framework 4.5
Click to download demo
Note: jmeter,: http://jmeter.apache.org/
. Net memory Analysis Using CLR profiler,: http://search.microsoft.com/en-us/DownloadResults.aspx? Q = CLR % 20 profiler
References:
Java and Mode
Head first design model
Uncle Tom: Don't let the interviewer ask you a single example.
<Full text>
Author: Wu Jian
Source: http://www.cnblogs.com/wu-jian/
The copyright of this article is shared by the author and the blog Park. You are welcome to repost it, but you must specify the source and provide the original article connection clearly on the article page. Otherwise, you will be held legally liable.