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,尤其在运行时。