NoClassDefFoundError 线上异常总结

11-Jul-2019 15:45:10.758 SEVERE [catalina-exec-2] org.springframework.boot.web.servlet.support.ErrorPageFilter.forwardToErrorPage Forwarding to error page from request [/mjyx/search] due to exception [null] java.lang.ExceptionInInitializerError at 
...
xxx.xxx.xxx.Handler.invoke(XXXHandler.java:42) at 
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.IllegalArgumentException at java.util.concurrent.ThreadPoolExecutor.<init>(ThreadPoolExecutor.java:1307) at xxx.xxx.xxx.ThreadPoolConfig.<clinit>(ThreadPoolConfig.java:17) ... 73 more
org.springframework.boot.web.servlet.support.ErrorPageFilter.forwardToErrorPage Forwarding to error page from request [/aaa/bbb] due to exception [Could not initialize class xxx.xxx.xxx.ThreadPoolConfig] java.lang.NoClassDefFoundError: Could not initialize class xxx.xxx.xxx.ThreadPoolConfig at 

以上是线上异常报错, tail -f第一感觉是类未找到。代码在线下测试通过,并在出现问题后,将线上jar 包download 到本地测试也正常。
进一步找详细报错信息,ThreadPoolConfig的17行及ThreadPoolExecutor的1307行

  • ThreadPoolConfig 17行

public class ThreadPoolConfig {

 ...
    public static final ExecutorService POOL_EXECUTOR = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), SEARCH_THREAD_FACTORY, new ThreadPoolExecutor.AbortPolicy());
  ...
  

ThreadPoolExecutor的1307行 JDK 代码

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,  1307 行
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

从表现上来看可能是BlockingQueue 构造问题

 public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

查看以上构建方法capacity =1024 不可能报异常,进一步查看
ThreadPoolExecutor构造参数,有可能出问题的是

  if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();

查看

 public static final ExecutorService POOL_EXECUTOR = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, 20, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), SEARCH_THREAD_FACTORY, new ThreadPoolExecutor.AbortPolicy());

coreSize 取物理机核数,有可能线上物理机核数与线下机器核数不一致造成。
修改coreSize 后结果正常。

/**
 * Thrown if the Java Virtual Machine or a <code>ClassLoader</code> instance
 * tries to load in the definition of a class (as part of a normal method call
 * or as part of creating a new instance using the <code>new</code> expression)
 * and no definition of the class could be found.
 * <p>
 * The searched-for class definition existed when the currently
 * executing class was compiled, but the definition can no longer be
 * found.
 *
 * @author  unascribed
 * @since   JDK1.0
 */
public
class NoClassDefFoundError

该类注释发现,该异常是虚拟机在或classloader 构造类的运行时,未找到该类的definition,而该类在编译时是存在的。
···
而异常ClassNotFoundException

/**
 * Thrown when an application tries to load in a class through its
 * string name using:
 * <ul>
 * <li>The <code>forName</code> method in class <code>Class</code>.
 * <li>The <code>findSystemClass</code> method in class
 *     <code>ClassLoader</code> .
 * <li>The <code>loadClass</code> method in class <code>ClassLoader</code>.
 * </ul>
 * <p>
 * but no definition for the class with the specified name could be found.
 *
 * <p>As of release 1.4, this exception has been retrofitted to conform to
 * the general purpose exception-chaining mechanism.  The "optional exception
 * that was raised while loading the class" that may be provided at
 * construction time and accessed via the {@link #getException()} method is
 * now known as the <i>cause</i>, and may be accessed via the {@link
 * Throwable#getCause()} method, as well as the aforementioned "legacy method."
 *
 * @author  unascribed
 * @see     java.lang.Class#forName(java.lang.String)
 * @see     java.lang.ClassLoader#findSystemClass(java.lang.String)
 * @see     java.lang.ClassLoader#loadClass(java.lang.String, boolean)
 * @since   JDK1.0
 */
public class ClassNotFoundException extends ReflectiveOperationException {
  

是该类在编译期压根就不存在,当运行时用class.forName时,找不到类报异常.
综上两点总结

  • NoClassDefFoundError与 ClassNotFoundException不同,不要被该异常转移注意力。
  • 注意线程池的coreSize不要大于maxSize,尤其在运行时。
    原文作者:zh_harry
    原文地址: https://www.jianshu.com/p/382b7a04a3cc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞