Open yhzdys opened 1 day ago
项目中的一些组件需要一个独立的JSONUtil工具类,通过自定义ObjectReaderProvider来实现一些自定义的逻辑。 在项目启动时,如果有多个并发请求同时调用JSON的静态方法和自定义的JSONUtil,有概率出现线程死锁。
排查下来的原因是:
类ObjectReaderProvider和JSONFactory的静态代码块出现了循环依赖。 类加载器在初始化class时会给上一个class级别的锁以保证类的static代码只执行一次。
ObjectReaderProvider中的static代码块需要依赖JSONFactory完成初始化, 但是JSONFactory中的defaultObjectReaderProvider静态属性需要依赖ObjectReaderProvider完成初始化。
运行下面代码,可能出现死锁,导致系统无响应。
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.reader.ObjectReaderProvider; import com.alibaba.fastjson2.writer.ObjectWriterProvider; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; public class Test { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(2); Thread thread1 = new Thread(() -> { System.out.println("1 start"); LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(10L)); // 停顿时间可能需要根据环境调整 JSONUtil.test(); latch.countDown(); }, "thread-1"); Thread thread2 = new Thread(() -> { System.out.println("2 start"); JSON.parseObject("{}"); latch.countDown(); }, "thread-2"); thread1.start(); thread2.start(); System.out.println("waiting"); latch.await(); System.out.println("finished"); } public static class JSONUtil { private static final ObjectReaderProvider READER; private static final ObjectWriterProvider WRITER; static { // 解决方法,随便调一个JSONFactory的方法来保证加载顺序与默认顺序一致 // JSONFactory.getDefaultObjectReaderProvider(); READER = new ObjectReaderProvider(); WRITER = new ObjectWriterProvider(); } public static String test() { return "ok"; } } }
目前时通过JSONUtil中注释掉的方法来保证类的加载顺序一致。 但是这种静态代码循环依赖的形式,并非一种好的实现,一旦出现问题很难排查,或许有改进的必要?
1 start 2 start waiting
问题描述
项目中的一些组件需要一个独立的JSONUtil工具类,通过自定义ObjectReaderProvider来实现一些自定义的逻辑。 在项目启动时,如果有多个并发请求同时调用JSON的静态方法和自定义的JSONUtil,有概率出现线程死锁。
排查下来的原因是:
类ObjectReaderProvider和JSONFactory的静态代码块出现了循环依赖。 类加载器在初始化class时会给上一个class级别的锁以保证类的static代码只执行一次。
ObjectReaderProvider中的static代码块需要依赖JSONFactory完成初始化, 但是JSONFactory中的defaultObjectReaderProvider静态属性需要依赖ObjectReaderProvider完成初始化。
环境信息
重现步骤
运行下面代码,可能出现死锁,导致系统无响应。
期待的正确结果
目前时通过JSONUtil中注释掉的方法来保证类的加载顺序一致。 但是这种静态代码循环依赖的形式,并非一种好的实现,一旦出现问题很难排查,或许有改进的必要?
相关日志输出
附加信息