There are times when only one class is required in a program to produce a unique instance. For example, a Recycle Bin object in a Windows system. Regardless of which disk we delete data from, the deleted data is placed in the same Recycle Bin. A singleton design pattern is used here.
Let's use the code to illustrate the singleton design pattern in Java. The core idea is to privatize the constructor and then use the static method to obtain the instance.
RecycleBin Class Code:
Package Org.lyk.demo; public classpublic static RecycleBin uniqueinstance; private RecycleBin () {} public staticif (null == Recyclebin.uniqueinstance) {recyclebin.uniqueinstance = new RecycleBin (); } return Recyclebin.uniqueinstance;}}
Main method:
Package Org.lyk.demo; public classpublic static RecycleBin uniqueinstance; private RecycleBin () {} public staticif (null == Recyclebin.uniqueinstance) {recyclebin.uniqueinstance = new RecycleBin (); } return Recyclebin.uniqueinstance;}}
The above code output results are as follows:
Bin1 = = Bin2:true Bin1.hashcode (): 31168322 Bin2.hashcode (): 31168322
As you can see, bin1 and bin2 are exactly the same.
However, the above code is problematic. If we are writing multi-threaded, we will encounter problems. Multiple instances may be generated when more than one thread calls getinstance at the same time. Take a look at the following code:
RecycleBin class:
PackageOrg.lyk.demo;ImportJava.lang.Thread; Public classRecycleBin { Public StaticRecycleBin uniqueinstance; PrivateRecycleBin () {} Public StaticRecycleBin getinstance () {if(NULL==recyclebin.uniqueinstance) {Try{Thread.Sleep (3000); }Catch(interruptedexception e) {e.printstacktrace (); } recyclebin.uniqueinstance=NewRecycleBin (); } returnrecyclebin.uniqueinstance; }}
The worker class that implements the Runnbale interface:
PackageOrg.lyk.demo;Importjava.lang.Runnable; Public classWorkerImplementsRunnable {PrivateRecycleBin bin; PublicWorker () {} Public voidrun () { This. bin =recyclebin.getinstance (); } PublicRecycleBin Getrecyclebin () {return This. bin; }}
Main Method Code:
PackageOrg.lyk.demo;//import java.util.Date; Public classHello { Public Static voidMain (string[] args)throwsException {Worker worker1=NewWorker (); Worker Worker2=NewWorker (); Thread T1=NewThread (Worker1); Thread T2=NewThread (WORKER2); T1.start (); T2.start (); T1.join (); T2.join (); RecycleBin bin1=Worker1.getrecyclebin (); RecycleBin bin2=Worker2.getrecyclebin (); Printinfo (bin1,bin2); } Public Static voidPrintinfo (RecycleBin bin1, RecycleBin bin2) {System.out.println ("Bin1 = = bin2:" + (bin1==bin2)); System.out.println ("Bin1.hashcode ():" +Bin1.hashcode ()); System.out.println ("Bin2.hashcode ():" +Bin2.hashcode ()); }}
Output Result:
Bin1 = = Bin2:false
Bin1.hashcode (): 31168322
Bin2.hashcode (): 17225372
It can be seen that, after the introduction of multi-threading, if the code that creates the RecycleBin instance is not synchronized, then our singleton mode fails. There are roughly three solutions.
One) is initialized directly when declaring a variable. This practice is simple and rude, and it is not recommended if you initialize a singleton object with a good resource. Because as soon as the class is loaded, the object is created. If we don't use this instance at all in our code, it's certainly a waste of resources.
The code is as follows:
RecycleBin class
PackageOrg.lyk.demo;ImportJava.lang.Thread; Public classRecycleBin { Public StaticRecycleBin uniqueinstance =NewRecycleBin (); PrivateRecycleBin () {} Public StaticRecycleBin getinstance () {//if (null = = Recyclebin.uniqueinstance)// {//Try// {//Thread.Sleep (+);//}catch (interruptedexception e)// {//e.printstacktrace ();// }//recyclebin.uniqueinstance = new RecycleBin ();// } returnrecyclebin.uniqueinstance; }}
Operation Result:
Bin1 = = Bin2:true
Bin1.hashcode (): 31168322
Bin2.hashcode (): 31168322
b) Use the synchronization method. The disadvantage of this is that locking the method will also reduce the efficiency of the program operation.
The RecycleBin code is as follows:
PackageOrg.lyk.demo;ImportJava.lang.Thread; Public classRecycleBin { Public StaticRecycleBin uniqueinstance; PrivateRecycleBin () {} Public Static synchronizedRecycleBin getinstance () {if(NULL==recyclebin.uniqueinstance) {Try{Thread.Sleep (3000); }Catch(interruptedexception e) {e.printstacktrace (); } recyclebin.uniqueinstance=NewRecycleBin (); } returnrecyclebin.uniqueinstance; }}
Operation Result:
Bin1 = = Bin2:true
Bin1.hashcode (): 31168322
Bin2.hashcode (): 31168322
III) use double judgment. This ensures both multithreaded code synchronization and the performance loss caused by each call to lock function.
The RecycleBin code is as follows:
PackageOrg.lyk.demo;ImportJava.lang.Thread; Public classRecycleBin { Public StaticRecycleBin uniqueinstance; PrivateRecycleBin () {} Public StaticRecycleBin getinstance () {if(NULL==recyclebin.uniqueinstance) {synchronized(RecycleBin.class) { if(NULL==recyclebin.uniqueinstance) {Try{Thread.Sleep (3000); }Catch(interruptedexception e) {e.printstacktrace (); } recyclebin.uniqueinstance=NewRecycleBin (); } } } returnrecyclebin.uniqueinstance; }}
The results of the operation are as follows:
Bin1 = = Bin2:true
Bin1.hashcode (): 31168322
Bin2.hashcode (): 31168322
The singleton design pattern is often encountered both in development and when we are looking for a job interview. So simply write a single code is not enough, the interview must be multi-threaded synchronization principle and method to speak out, this is what the interviewer really want.
Java single-Instance design pattern