When writing software, you often need to use a print log function, which can help you debug and position the problem. After the project is launched, it can also help you analyze the data. But Java's native system.out.println () method is rarely used in real project development, and even code checking tools such as Findbugs will think that using System.out.println () is a bug.
Why is System.out.println (), which is a novice artifact of Java, will be spurned in the real project development? In fact, as long as you analyze it carefully, you will find many disadvantages of it. For example, if it is not controlled, all the logs will be printed as usual after the project is launched, thereby reducing the operating efficiency; or it cannot record the log to the local file. Once the print Distinguishing, it will be difficult for you to distinguish which category this log is printed in.
Your leader is not a fool. He is also clear with the disadvantages of all System.out.println (). Therefore, the task he gives you today is to make a log tool class to provide better logo. However, your leader is pretty good, and it does not allow you to achieve a Niubi log tool with various functions at the beginning. It only needs a log tool that can control the printing level.
This demand is not difficult for you. You immediately started writing and quickly completed the first version:
Public class logutil {public final into debug = 0; public final into = 1; portal int error = 2; public final instation = 3; public into = Debug; Public Void Debug (String MSG) {if (debug> = level) {system.out.println (msg);}} Public Void Info (String msg) {if (info> = level) {system.out.println (msg);} public void Ing msg) { if (error> = level) {system.out.println (msg);}}}
Print the log through this class, and only need to control the level of the level to freely control the printing content. For example, the project is now in the development stage, and the level is set to debug, so that all the log information will be printed. If the project is online, you can set the level to Info, so that you can only see the log and the above level log printing. If you just want to see the wrong log, you can set the level to ERROR. And if the project you develop is a client version, you don't want to print any log, you can set the level to nothing. You only need to call when printing:
new logutil (). Debug ("Hello World!");
You can't wait to introduce this tool to your leader. After listening to your introduction, your leader said, "Good, everyone will print the log with this tool in the future!"
But it didn't take long for your leader to find you to give feedback. He said that although this tool is easy to use, it does not distinguish between printing such things. Every time you need to print a log, you need to produce a new logutil, which takes up too much. I hope you can change this tool to use it to use it. Single mode implementation.
Do you think your leader is very reasonable, and you are trying to take advantage of this opportunity to practice the design mode, so you wrote the following code (PS: The code here is done by myself, and I didn’t pay attention to it. I didn’t pay attention to it. Thread synchronization problem):
Public class logutil {Private Static Logutil Logutilinstance; Public Final Int Debug = 0; Public Final INT Info = 1; Public Final = 2; Publi C flity int Nothing = 3; port level = debug; private logutil () {} public Static Logutil GetInstance () {if (logutilinstance == null) {logutilinstance = new logutil ();} Return LogutilinStance;} Public Void Debug (String g. {if (debug> = level) {system.out.println (msg) ;}} Public Void Info (String msg) {if (info> = level) {system.out.println (msg);} public void error (string msg) {if (error> = level) {System .out. Println (msg);}} Public Static Void Main (String [] Args) {Logutil.getInstance (). Debug ("Hello World!");}}
First of all, the logutil's constructor is privatized, so that the new keyword cannot be used to create a Logutil instance. Then use a slogutil private static variable to save the instance, and provide a public GetInstance method to obtain a Logutil instance. In this method, it is determined that if the slogutil is empty, a new Logutil instance is available, otherwise it will return the slogutil directly. This can ensure that there will only be an instance of Logutil in the memory. Single mode is completed! At this time, the code of the print log needs to be changed to the following way:
Logutil.getinstance (). Debug ("Hello World");
You show this version to your Leader. He smiled after watching it, saying, "Although this seems to be a single example, there is still a bug.
You are full of suspicion, isn't the single -example mode realized like this? What can be bug?
Your leader prompts you that using a singles mode is to make this class only have one instance in memory, but do you consider the situation of printing logs in multi -threaded? As shown in the following code:
Public Static Logutil GetInstance () {if (logutilinstance == NULL) {logutilinstance = new logutil ();} Return LogutilinStance;}
If there are two threads at the same time executing the getInstance method at the same time, the first thread just executes the second line and has not yet executed the third line. At this time Enter the IF judgment. In this way, your singles mode fails because two different instances are created.
You suddenly realize, but your thinking is very fast, and you immediately think of the solution. You only need to add a synchronous lock to the method. The code is as follows:
Public Synchronized Static Logutil GetInstance () {if (LogutilinStance == NULL) {LogutilinStance = New Logutil ();} Return LogutilinStance;}
In this way, only one thread is allowed to execute the code in Getinstance at the same time, which effectively solves the situation where the two instances will create above.
Your leader reads your new code and said, "Well, yes. This does solve the situation that may create two instances, but this code is still a problem."
You are nervous, why are there any problems?
Your leader smiled: "Don't be nervous, this time it is not a bug, but it can be optimized in terms of performance. Look, if you add a Synchronized method to the getinstance method, then every time I go to the GetinStace method, I will be synchronized. The effect of locking will reduce the efficiency of this operation. In fact, just add a synchronous lock when creating a Logutil instance for the first time.
First remove the synchronized keyword from the method statement, and add it to the method body:
Public Static Logutil GetInstance () {if (logutilinstance == null) {Synchronized (logutil.class) {if (logutilinstance == null) {// It may be necessary because the two processes may be attached at the same time at the same time at the same time. Logutilinstance = before synchronized = new logutil ();}}} Return Logutilinstance;}
After the code is changed to this, it will enter the third line when the slogutil is not initialized, and then add the synchronous lock. As soon as the slogutil is initialized, it will no longer go to the third line, so that the Getinstance method will not be affected by synchronization locks, and the efficiency will be improved to a certain extent.
You can't help but admire. This method is really clever. It is too smart to think of it.
Your leader immediately became humble: "This method is called Double-Check Locking, but I don't think of it. You can check more information on the Internet."
In fact, I am more accustomed to using the hungry man mode in Java
The characteristic of lazy -style is delayed loading.
The characteristic of the hungry Han style is that it is loaded at the beginning, so you can return directly when you use it (I recommend this one more, because there is no need to consider too many thread security issues. Of course The dual locks mentioned to solve the synchronization problem)
The code of implementing log records with hungry Han style is as follows:
Public Class Logutil {Private Static Final LogutilinStance = New Logutil (); Public Final Int Debug = 0; Public Final INFO = 1; Public Fina l int Error = 2; Public Final Int Nothing = 3; Public Int level = Debug; Private Logutil () {} Public Static Logutil GetInstance () {Return LogutilinStance;} Public Void Debug (String msg) {IF (Debug> = Level) {system.out.print ln (msg);}} Public Void Info (String MSG) {if (info> = level) {system.out.println (msg);}} public void error (string msg) {if (error> = level) {system.out.println (msg);} public atic void main (string [] art) {logutil.getinstance (). Debug ("Hello World!");}}