The features that the log service needs to provide are:
The log service can be turned on and off externally and securely;
A log message can be safely logged by multiple threads;
After the log service is closed, the remaining non-logged messages can be written to the log file;
Public classlogservice{Private FinalBlockingqueue<string>Msgqueue; //Blocked message queue to save log messages Private Finalprintwrite Writer; //write message to log file Private FinalLoggerthread Logthread; //thread that writes logs Private BooleanIsShutDown; //Indicates whether the log service has been closed Publiclogservice (String file) throws FileNotFoundException {Logthread=NewLogthread ();
writer = new Printwrite (file); } Public voidstart () {Logthread.start (); //Start log thread Runtime.getruntime (). Addshutdownhook (NewThread () { ///Add close hook to ensure that the log file will eventually close stop () without calling the Stop method ; }); } Public voidStop () {synchronized( This) //need to lock first, and then modify the value of IsShutDown {if(!IsShutDown) {IsShutDown=true; Logthread.interrupt (); //Interrupt log thread } } } Public voidlog (String message) {synchronized( This) //need to lock first, and then access the value of IsShutDown {if(!IsShutDown) //If the log service is not closed, the message is added to the message queue, which is a typical prior condition, stating that IsShutDown is volatile and does not resolve the problem of synchronization msgqueue.put (message); Else Throw NewIllegalStateException ("Log Service is shutdown"); //If the log service is closed, throw illegalstateexception } } Private classLoggerthreadextendsThread { Public voidrun () {Try { while(true) { Try { synchronized(Logservice. This) { if(IsShutDown && msgqueue.size () = = 0) //Close the log thread if the service is closed and there are no remaining messages in the message queue Break; Writer.write (Msgqueue.take ()); } } Catch(Interruptedexception ex) {} //Ignore interrupt message }} finally{writer.close (); //close log file } } } }
In the example above, there are several places worth noting:
The log service should not stop immediately when it receives a shutdown message, but should write the remaining messages in the message queue to the log file before closing. If you decide to discard these messages, you should clear the message queue first, or the thread that calls the log method will always block;
In the previous example, using IsShutDown to identify whether a service has been closed, the thread calling the log method first detects the value of IsShutDown so that multiple threads need to isshutdown mutually exclusive access, rather than simply using the volatile modifier isshutdown;
In the log thread, when the interrupt message is detected, it is ignored, and finally there is no recovery in the interrupt state, because we know that the owner log service of the thread has been stopped, no longer need to resume the interrupt;
In the example above, the closure hook was used, and the close hook thread was added to the start method to ensure that the log service would eventually shut down before the JVM stopped, even if the caller did not call the Stop method to halt the log service;
Here's a quick introduction to closing the hooks:
Closing a hook is a thread that is registered through the Runtime.addshutdown method but does not start the task immediately, and the JVM starts execution of the closed hook thread that has already been registered during the shutdown process. Closing a hook is typically used to clean up a service or application, and it is not advisable to perform time-consuming tasks in it, delaying the JVM's shutdown.
Reference "Java Concurrency Programming Combat"
Java Concurrency Programming (vi) An example of a log service