Single case Mode
A single case pattern is used very frequently in programming, designed to provide only one object in a program (guaranteed to be constructed only once), such as log objects written to logs, and Windows Task Manager implementation (only one can be opened). Here we mainly introduce the implementation of Java for the single example mode (including a Hungry man and lazy). Implement
Here, using the log class as an example, the log object needs to have only one object in the program and initialize it only once. a hungry man type
The A hungry man model is easy to understand and initializes an object that requires a single instance when the class is loaded. Implementation is also relatively easy.
public class singleton{
private static Log logobj = new Log ();
public static Log getinstance () {return
logobj
}}
Lazy Type
If the logobj needs to take up a lot of memory, if the logobj is initialized at the beginning, it consumes a lot of memory. At this point, some people think, if I want to use the time to initialize the Log class objects, like lazy, only when the use of the initialization, how to design it. implement one (non-thread safe version)
public class singleton{
private static Log logobj = null;
public static Log getinstance () {
if (logobj = = null) {
logobj = new Log ();
}
Return logobj
}
}
implementing two (thread-safe versions)
public class singleton{
private static Log logobj = null;
public static synchronized Log getinstance () {
if (logobj = null) {
logobj = new log ();
}
Return logobj
}
}
In order to achieve thread safety, this version of the implementation of the sacrifice of a certain degree of efficiency, if the logobj has been initialized, then other threads also need synchronous access to the GetInstance method, can cause efficiency loss. As a result, some people implemented the following version. implement three (wrong version)
public class singleton{
private static Log logobj = null;
public static Log getinstance () {
if (logobj = = null) {
synchronized (singleton.class) {
if (logobj = null) {
logobj = new Log ();
}}} Return logobj
}
}
At first glance it looks like the above version is no problem, if a thread a finds that the logobj has not been initialized, then enters the synchronization block to initialize the Logobj, and if another thread B enters during that time, thread B waits to enter the sync block, waits for a thread to exit the sync block, and the logobj is initialized, B After the thread enters the synchronization block, it finds that logobj is not NULL, exits the sync block, and no longer initializes the logobj. This enables both thread safety and efficiency, and is really a smart way to encode. The problem, however, is that the existence of a command reordering causes the log to be logobj before it is fully initialized. This may cause other threads to get an object that is not fully initialized. Solving Method
The JDK1.5 version extends the volitile semantics to ensure the correctness of the above code, so long as the logobj is declared as Volitile (only the visibility of the memory is guaranteed before volitile).
Use static inner classes.
When a class is loaded, its inner classes are not loaded at the same time. A class is loaded and occurs only if one of its static members (static domain, constructor, static method, and so on) is invoked.
And the JVM guarantees thread-safety problems with class loading, so use this feature to write versions that are both efficient and thread-safe. implement four (take into account efficiency and thread-safe versions)
public class singleton{
static class logholder{
static Log logobj = new Log ();
}
public static Log getinstance () {return
logholder.logobj
}}
In this way, when the singleton class loads, the Logholder is not loaded and the log is not initialized, and if the thread accesses the GetInstance method, the JVM first loads the Logholder class and guarantees initialization Logobj and finally returns LOGOBJ.