使用Kryo 5.2.0偶发找不到类序列化异常,重启Tomcat临时解决如何处理?
你碰到的异常核心是Kryo实例被多线程并发访问导致内部读取字节流错位,错误的把业务字段值Ethiopian Airlines当成了需要加载的类名触发了类找不到异常,偶发、重启后暂时恢复的特征完全符合多线程资源竞争的表现。
根因定位
- 最核心的问题是Kryo池的线程安全参数配置错误:Kryo实例本身是线程不安全的,不支持多线程同时操作,你当前池构造的第一个参数
KRYO_INSTANCE_THREAD_SAFE如果设置为true,池会允许同一个Kryo实例被多个线程并发调用,导致内部的字节读取指针、状态变量被篡改,读取类名的时候读取到了后续的业务字符串内容,触发异常。 - 次要潜在问题:你注释了类加载器配置行,Tomcat的Webapp类加载器会在运行时发生上下文切换,Kryo默认使用的类加载器可能无法正确加载业务类。
- 其他可能问题:Kryo实例使用完未正确归还、序列化和反序列化的Kryo配置不一致也会触发字节流解析错位。
解决方案
- 修正Kryo池的线程安全配置,将构造函数第一个参数强制设为
false,同时打开类加载器配置:
// 第一个参数表示池内对象是否线程安全,Kryo线程不安全必须设为false private static final Pool<Kryo> kryoPool = new Pool<Kryo>(false, true, KRYO_POOL_MAXIMUM_CAPACITY) { protected Kryo create() { final Kryo kryo = new Kryo(); // 打开类加载器配置,明确指定Web应用的类加载器 kryo.setClassLoader(Thread.currentThread().getContextClassLoader()); kryo.setRegistrationRequired(false); // 生产环境建议打开该配置,方便排查未注册类的问题 kryo.setWarnUnregisteredClasses(true); kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy())); try { kryo.register(Class.forName("java.util.Collections$SynchronizedMap"), new SynchronizedCollectionsSerializer()); } catch (ClassNotFoundException e) { e.printStackTrace(); } SynchronizedCollectionsSerializer.registerSerializers(kryo); return kryo; } };
- 检查Kryo工具类的使用逻辑,确保所有场景下都是
borrowObject获取实例,使用完成后在finally块中调用returnObject归还实例,禁止归还后继续操作Kryo实例。 - 确认序列化和反序列化的Kryo配置完全一致,包括序列化器、类注册策略、参数配置等,避免两端配置不一致导致的字节流解析错误。
- 如果业务允许,建议开启
setRegistrationRequired(true),提前注册所有需要序列化的类,既可以提升序列化性能,也能彻底避免类名解析错误的问题。
内容的提问来源于stack exchange,提问作者Santosh
相关产品推荐
相关产品推荐

