<! -- @ Page {margin: 2 cm} H1 {margin-left: 0.16; margin-right: 0.16; margin-top: 0.16; margin-bottom: 0.16; background: # ffffff; color: #000000; background: # ffffff} H1.western {font-family: "Times New Roman"; font-size: 18pt} H1.cjk {font-family: "Times New Roman"; font-size: 16pt; font-style: normal; font-weight: bold} H1.ctl {font-family: "Times New Roman"; font-size: 16pt; font-weight: bold} P {margin-bottom: 0.21} A: link {so-language: zxx} -->
Singleton is very useful, but it is often the source of troubles. This article includes a variety of Singleton in my personal practice, as well as C ++ and Java.
Think about what Singleton is.
The Singleton mode is usually used when only one object is needed to survive. However, this sentence is not the full meaning of Singleton. It can be changed because the mode is not a formula. For example, a system prints only one object in a process, but a multi-threaded program that accesses the database concurrently may require a connection object for each thread, in this way, Singleton means that there are multiple processes, and each thread has one. But what if I can connect to multiple databases? It is very likely that only one connection object connected to a specific database is allowed in each thread.
Singleton implementers must provide users with a global access point. The simplest is the static member function Instance. Why not use global variables? Because global variables cannot prevent others from creating variables of the same type, the global space is also polluted (others cannot use the same variables as you ). So we need to change the class constructor to protected. An object can save a static pointer, instantiate it inside the Instance function, and return it. This solution can solve the requirements of the printer just now. An object can save a static map. Each map item stores the thread ID and static object pointer, and provides a series of methods to maintain the map, in this way, each thread needs to have an object. But is that enough? I still encounter a different requirement, requiring the runtime to decide to create different objects. In this case, you can add parameters to the Instance function to create different objects through parameters. These objects can also be derived from the parent Singleton class. Maybe each thread allows no more than three objects. It doesn't matter. We can implement these control logics within the Instance.
What I want to express is that Singleton can have many variants, and sometimes it may make you feel inferior, but this is the charm of design patterns. I am also a dogmatism from the very beginning to be able to accept many wonderful changes. Sometimes I shouldn't even use it. Maybe many of them are just polymorphism.
C ++
Http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf: Scott Meyers and Andrei Alexandrescu.
1) do not use static or global variables to implement Singleton
C ++ cannot guarantee the calling sequence and destructor sequence of the constructors of static or global objects. Therefore, if there are multiple Singleton classes implemented using this method in the program, there is another constructor dependency and destructor dependency between them, which will cause disastrous consequences. Therefore, this implementation is appropriate only when there is certainly no constructor or destructor dependency. However, for C ++, it is simpler and more convenient to use another static object method. Therefore, this method can basically be abandoned.
2) Meyers Singleton controls the construction sequence, but does not control the structure sequence.
Scott Meyer proposed a solution in <strong tive C ++> 3rd Item4 when moving the non-local static variable to the static method to become the local static variable. C ++ makes sure that this static variable is created only when the first static method is called. But here is a question: the order of creation can be controlled, but what about the structure order? We only know that at the end of the process, the local static variable will be destructed and executed in reverse order of creation. If the destructor of several Singleton classes also have dependencies, and the dependency order conflicts with the LIFO sequence, the dead-reference problem will occur.
3) Andrei briefly describes the solution concept mentioned in <Modern C ++ Designe> Chapter 6th as follows:
A. Use new to allocate Singleton objects,
B. Each Singleton object has an integer life counter with a long life cycle.
C. Use a specially designed array to save the pointer to the Singleton object to be destroyed. The longer the lifetime is always in front of the array, and the same lifetime is arranged from the beginning to the end in the order of creation.
D. Register a cleanup function in std: at_exit. This function always extracts the last pointer from the array described in c and then calls delete.
4) multithreading is supported. After being able to control the structure and structure sequence, we now consider multithreading. The Double-Checked Locking mode is generally used. No lock is required for the first check, but the second check and creation object must be locked. Note that the compiler may optimize the code and cause the Double-Checked Locking mode to fail. Therefore, you must use volatile to modify the T * pInstance variable.
5) Loki finally proposes a policy-based SingletonHolder class, which perfectly solves the above problems. Note that SingletonHolder only supports normal Singleton, which is the unique object in the process. SingletonHodler provides more policy classes to meet different requirements. For details, refer to the Loki document or. SingletonHolder receives three policy classes, which are used to manage the creation and destruction objects, lifecycle and thread policies respectively. Reference books can be used for specific examples.
6) ACE and boost provide their own solutions. Compared with SingletonHolder, SingletonHolder is more flexible and can handle various situations.
SingletonHolder example:
Download the latest source code, set the include directory in your C ++ program, and add singleton. cpp to makefile.
# Include <cstdlib>
# Include "loki/Singleton. h"
# Include <iostream>
Using namespace std;
Class MyClass {
Public:
Void ShowPtr ()
{
Cout <this <endl;
}
};
Unsigned int GetLongevity (MyClass *){
Return 1;
}
/*
*
*/
Int main (int argc, char ** argv ){
MyClass c = Loki: SingletonHolder <MyClass, Loki: CreateUsingNew, Loki: SingletonWithLongevity >:: Instance (); // in a single-threaded environment, use new and delete to create and destroy objects, and use GetLongevity to define the lifetime.
C. ShowPtr ();
Return 0;
}
To support multithreading, define the macro LOKI_CLASS_LEVEL_THREADING in your application. Create with the following code:
MyClass c = Loki: SingletonHolder <
MyClass,
Loki: CreateUsingNew,
Loki: SingletonWithLongevity,
Loki: ClassLevelLockable,
Loki: Mutex
>:: Instance ();
Since it is Singleton in a multi-threaded environment, Mutext should be used for synchronization and volatile should be used to forcibly read data from the memory.
SingletonHolder only supports the standard Singleton, which is unique within the process. The Singleton variant is not supported. For example, each thread has only one object, or in other cases, we need to design it ourselves.
Java
1. public static final member variable, and change the constructor to private. The client program can directly access the member variable.
2. private static final member variable. Then, the engineering method getInstance () is provided to return static member variables. Due to the flexibility brought by the factory method, we can talk about the unique object in the process and change it to the unique object in the thread. When modifying the implementation code of the getInstance method, the call of the Customer Code is not affected.
3. It is best not to implement the Serializable interface for the Single class. Because each deserialization generates an object as a new object, it breaks the Singleton principle. As a remedy, you can declare all member variables as transient and provide a readResolve method. All member variables are not involved in the serialization and deserialization processes, and readResolve always returns a Singleton object. In fact, these actions do not support serialization. Therefore, the best choice is not to implement the Serializable interface.
4. Single-element Enumeration type. The usage is similar to 1, which is very simple. But it also implements the Serializable interface and can automatically prevent deserialization from generating new objects. If you do not consider the thread, this is better than the preceding three methods.
// Enum singleton-the preferred approach
Public enum Elvis {
INSTANCE;
Public void leaveTheBuilding (){...}
}
5. Delayed creation (On-demand creation or lazy Mode)
Bob Lee, engineer at Google, wrote a new lazy Singleton model.
Public class Singleton {
Private static class SingletonHolder {
Private static final Singleton INSTANCE = new Singleton ();
}
Private Singleton (){
}
Public Singleton getInstance (){
Return SingletonHolder. INSTANCE;
}
}
SingletonHolder is not loaded when singleton is loaded. SingletonHolder is loaded only when SingletonHolder is called when getInstance () is called. Therefore, singleton constructor is called to instantiate singleton, to achieve the lazy loading effect.
6. The Double-checked Locking mode is not available in Java. There are two reasons:
First, the Java compiler is being optimized, and the generated code is not in the order we write. It is very likely that the instance variable is assigned a value first, and then the object is constructed. In this way, in a multi-threaded environment, an error is returned when the result is determined based on instance = null.
Second, Java synchrorized ensures that the protected variables always read data from the memory, rather than using the data cached by registers. However, when the first thread has already created an object and other threads access it again, the data in the memory is not re-read because the synchronized protection code is not entered, therefore, the old version of data may be obtained.
For detailed reasons, refer to the following articles and other articles:
Html> http://dev.firnow.com/course/3_program/java/javashl/2008414/110150.html