Cause analysis and avoidance of thread leakage in Java application

Source: Internet
Author: User
Tags stack trace stub log4j


Cause-Log loss

Production on the issue of a few log loss, we log every hour to generate a file, and then every hour just to the point of time to switch to generate a new file and then the normal output of the log, to a fixed point on the empty, only a regular cleanup data threads hit a few lines of log.

Through analysis, because our application is deployed on the WebLogic, each time the war package is re-sent does not restart the WebLogic, just stop the previous application, restart a new one, and the previous application has an individual thread failed to shut down, with the new application at the same time logging, there is a problem.

The log4j of the leaking thread and the thread of the new application are each holding a appender, the key two appender rules are exactly the same.

650) this.width=650; "src=" Https://s1.51cto.com/wyfs02/M01/8E/90/wKioL1jFbBqjUBcpAACto1TwXtk741.jpg "title=" Jvm.jpg "alt=" Wkiol1jfbbqjubcpaacto1twxtk741.jpg "/>

The thread of the new application has been printing the log, switching on the whole point, and the leaking thread wakes up once every half an hour, and then prints a few lines of log.

Let's take a look at the code for log4j switching logs:

 /**     Rollover the current file to a new  File.  */  void rollover ()  throws IOException {     /* compute filename, but only if datepattern is specified * /    if  (datepattern == null)  {       Errorhandler.error ("Missing datepattern option in rollover ().");       return;    }    String  Datedfilename = filename+sdf.format (now);    // it is too  early to roll over because we are still within the     // bounds of the current interval. rollover will occur  once the    // next interval is reached.    if  (Scheduledfilename.equals (datedFilename))   {      return;    }    // close  current file, and rename it to datedFilename     This.closefile ();     //!!!!!!!!!! Focus on this!!!     //If there are already duplicate names, delete them.     file target  = new file (Scheduledfilename);     if  (Target.exists ())  {      target.delete ();     }    file file = new file (FileName);     Boolean result = file.renameto (target);     if (Result)  {       loglog.debug (filename + " -> " + scheduledfilename);     } else { &nbSp;    loglog.error ("failed to rename [" +filename+ "] to [" + Scheduledfilename+ "].");     }    try {      // this  will also close the file. This is OK since multiple       // close operations are safe.       this.setfile (filename, true, this.bufferedio, this.buffersize);     }     catch (ioexception e)  {      errorhandler.error ("Setfile (" +filename+ ",  true)  call failed.");     }    scheduledfilename = datedfilename;  }


If it is just 10 o ' clock, because the new application has been printing the log, 10 o'clock when a new log, and then keep playing logs, the results to 10:15, another appender also to hit the log, it found that 10 points, their original hold of the log or 9 points, switch one, If you find that you have a duplicate name, delete the rebuild, and that's why. But some people would say that the previous Appender held a file handle file was deleted, it should not be reported abnormal? After my experiment, there was no abnormal reaction.

public static void Main (string[] args) throws IOException {File A = new File ("test.txt");    BufferedWriter bw1 = new BufferedWriter (new FileWriter (a));    Bw1.write ("aaaaaaaa");    Bw1.flush ();    A.delete ();    Bw1.write ("aaaaaaaaa");    Bw1.flush ();    File B = new file ("Test.txt");    BufferedWriter bw2 = new BufferedWriter (new FileWriter (b));    Bw2.write ("bbbbbbbbb");    Bw2.flush ();    Bw1.write ("aaaaaaaaa"); Bw1.flush ();}

There is no exception to the above code, and the resulting file content is bbbbbbbbb.

This problem is only one of the problems caused by thread leaks, as well as other problems related to memory leaks. The next step is to analyze the causes of thread leaks and how to avoid such problems.


How does the application server clean up threads?


For some background threads in your app's own start-up, the application server will not normally stop you. Without knowing how WebLogic cleans these threads, and looks at Tomcat, Tomcat does not force these threads to shut down by default.

Let's look at a warning log in Tomcat:

July 27, 2016 7:02:10 pm Org.apache.catalina.loader.WebappClassLoaderBase clearreferencesthreads

Warning: The Web Application [Firefly] appears to had started a thread named [memkv-gc-thread-0] but had failed to stop it . This was very likely to create a memory leak. Stack trace of Thread:

Sun.misc.Unsafe.park (Native Method)

Java.util.concurrent.locks.LockSupport.parkNanos (locksupport.java:226)

Java.util.concurrent.locks.abstractqueuedsynchronizer$conditionobject.awaitnanos ( abstractqueuedsynchronizer.java:2082)

Java.util.concurrent.scheduledthreadpoolexecutor$delayedworkqueue.take ( scheduledthreadpoolexecutor.java:1090)

Java.util.concurrent.scheduledthreadpoolexecutor$delayedworkqueue.take ( scheduledthreadpoolexecutor.java:807)

java.util.concurrent.ThreadPoolExecutor.getTask (threadpoolexecutor.java:1068)

Java.util.concurrent.ThreadPoolExecutor.runWorker (threadpoolexecutor.java:1130)

Java.util.concurrent.threadpoolexecutor$worker.run (threadpoolexecutor.java:615)

Java.lang.Thread.run (thread.java:745)


In Tomcat about stopping these threads has a configuration that is off by default, and if it is on, it is used with the Stop method and is risky.

    /**     * Should Tomcat attempt to  terminate threads that have been started by the      * web application? Stopping threads is performed via the  deprecated  (For     * good reason)  <code>thread.stop () </ code> method and is likely to result in     *  instability. as such, enabling this should be viewed as an  option of last     * resort in a development  environment and is not recommended in a     *  production environment. if not specified, the default value of      * <code>false</code> will be used.     */     private boolean clearReferencesStopThreads = false;

I guess WebLogic is a similar strategy, so you can't expect the application server to clean up your threads.


Where should the thread be cleaned?


The correct way to stop applying a thread is to stop it yourself and not rely on the application server!

For example, using spring, you can take advantage of the Bean's Destroy method, or not spring, to register a listener.

public class Contextdestroylistener implements Servletcontextlistener {@Override public void contextinitialized (Ser Vletcontextevent SCE) {//TODO auto-generated method stub} @Override public void contextdestroyed (ServletContext Event SCE) {//TODO auto-generated method stub//cleanup thread in this place}}

We know where to clean up these threads, and then how to clean them up. Cleaning up the thread is not a shutdown method or a call to interrupt that simple thing.


How do I stop threads correctly?


To stop the thread yourself, first you have to get the handle of the thread, that is, the threaded object or the thread pool, and if you write the following code, you will not find the thread after the boot, so the thread must be able to get the handle when it cleans up the thread.

public static void Main (string[] args) {new Thread (new Runnable () {@Overridepublic void run () {while (true) {try {    Thread.Sleep (1000); System.out.println ("Wake Up");}    catch (Interruptedexception e) {e.printstacktrace ();} }}). Start ();}

The correct approach is to put the thread in a variable, such as T, and then stop the thread by T. The methods of stopping threads generally have stop,destroy,interrupt, but Stop,destroy have been discarded because they can cause deadlocks, so the usual practice is to use interrupt. The use of interrupt is similar to a signal, just like you in the Linux process to the sigterm signal ignored, it is impossible to kill the process through kill, interrupt is also the case. The following threads only report an exception, and the interrupt signal is ignored.

public static void Main (string[] args) {thread t = new Thread (new Runnable () {@Overridepublic void run () {while (tr    UE) {try {thread.sleep (1000);        System.out.println ("Wake Up");        } catch (Interruptedexception e) {e.printstacktrace ();    }    }}    });    T.start (); T.interrupt ();//Cannot stop thread}

This blocking thread, normally called by the function will be forced to check and throw interruption exception, similar to wait (), blocking the queue take, etc., in order for the program to shut down properly, interruptedexception best not to ignore.

public static void Main (string[] args) {thread t = new Thread (new Runnable () {@Overridepublic void run () {while (true) {TR Y {thread.sleep (1000); System.out.println ("Wake Up");} catch (Interruptedexception e) {e.printstacktrace (); System.out.println ("Stop ..."); break;}}}); T.start (); T.interrupt ();}

What if I don't throw interruptedexception in the Run method? For example, the following

public static void Main (string[] args) {thread t = new Thread (new Runnable () {@Overridepublic void run () {int i = 0;while (true) {i++;}}); T.start (); T.interrupt ();}

This situation requires the Run method to constantly check whether it is interrupted, or never stop.

public static void Main (string[] args) {thread t = new Thread (new Runnable () {@Overridepublic void run () {int i = 0;while (true) {i++;if (thread.interrupted ()) {System.out.println ("stop.."); Break;}}}); T.start (); T.interrupt ();}


Above is the correct way to stop a single thread, for the thread pool, there are generally two methods, shutdown and Shutdownnow, these two methods are very large, shutdown only thread pool no longer accept new tasks, but do not interrupt the running thread, And Shutdownnow will call the interrupt method on a thread-by-threaded basis, if your thread is certain that it can run over a period of time, you can use shutdown, but if it's a dead loop, or if it takes a long time to wake up, then use Shutdownnow, The implementation of runnable is then subject to the principle of a single thread above.



This article is from the "Niu Blog" blog, make sure to keep this source http://nxlhero.blog.51cto.com/962631/1905715

Cause analysis and avoidance of thread leakage in Java application

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.