文章目录

  • 问题场景
  • 问题环境
  • 问题原因
  • 解决方案
  • 结果
  • 总结
  • 扩展
  • 随缘求赞

问题场景

开发微服务项目的时候,发现数据库链接创建过程中,陷入了阻塞状态。表现形式为:程序输出日志之后,便卡死不动,不再显示新的日志。于是使用arthas进行问题跟踪,并根据发现的问题,针对性解决!

问题环境

软件 版本
JDK 1.8
springboot 2.1.1.RELEASE
hutool 5.5.5

问题原因

以下是使用arthas的有关命令,各位读者可以一览:

[arthas@22366]$ dashboard
ID              NAME                                           GROUP                          PRIORITY        STATE          %CPU            TIME            INTERRUPTED    DAEMON
46              Timer-for-arthas-dashboard-0cd6726c-c0c3-4fa0- system                         10              RUNNABLE       91              0:0             false          true
26              SimplePauseDetectorThread_0                    system                         9               TIMED_WAITING  8               0:0             false          true
31              Abandoned connection cleanup thread            main                           5               TIMED_WAITING  0               0:0             false          true
16              AsyncResolver-bootstrap-0                      main                           5               TIMED_WAITING  0               0:0             false          true
35              AsyncResolver-bootstrap-executor-0             main                           5               WAITING        0               0:0             false          true
36              Attach Listener                                system                         9               RUNNABLE       0               0:0             false          true
17              DiscoveryClient-0                              main                           5               TIMED_WAITING  0               0:0             false          true
34              DiscoveryClient-1                              main                           5               WAITING        0               0:0             false          true
33              DiscoveryClient-CacheRefreshExecutor-0         main                           5               WAITING        0               0:0             false          true
15              Eureka-JerseyClient-Conn-Cleaner2              main                           5               TIMED_WAITING  0               0:0             false          true
3               Finalizer                                      system                         8               WAITING        0               0:0             false          true
2               Reference Handler                              system                         10              WAITING        0               0:0             false          true
5               Signal Dispatcher                              system                         9               RUNNABLE       0               0:0             false          true
25              Thread-5                                       system                         9               WAITING        0               0:0             false          true
29              Thread-7                                       main                           5               BLOCKED        0               0:0             false          false
30              Timer-0                                        main                           5               TIMED_WAITING  0               0:0             false          true  [arthas@22366]$ thread --state BLOCKED
Threads Total: 29, NEW: 0, RUNNABLE: 7, BLOCKED: 1, WAITING: 11, TIMED_WAITING: 10, TERMINATED: 0
ID              NAME                                           GROUP                          PRIORITY        STATE          %CPU            TIME            INTERRUPTED    DAEMON
29              Thread-7                                       main                           5               BLOCKED        0               0:0             false          false
Affect(row-cnt:0) cost in 102 ms.[arthas@22366]$ thread 29
"Thread-7" Id=29 BLOCKED on java.lang.Class@5a6f639c owned by "main" Id=1at java.sql.DriverManager.registerDriver(DriverManager.java:334)-  blocked on java.lang.Class@5a6f639cat com.microsoft.sqlserver.jdbc.SQLServerDriver.<clinit>(SQLServerDriver.java:903)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at java.lang.Class.newInstance(Class.java:442)at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)at java.util.ServiceLoader$1.next(ServiceLoader.java:480)at java.sql.DriverManager$2.run(DriverManager.java:603)at java.sql.DriverManager$2.run(DriverManager.java:583)at java.security.AccessController.doPrivileged(Native Method)at java.sql.DriverManager.loadInitialDrivers(DriverManager.java:583)at java.sql.DriverManager.<clinit>(DriverManager.java:101)at oracle.jdbc.driver.OracleDriver.<clinit>(OracleDriver.java:188)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at java.lang.Class.newInstance(Class.java:442)at com.zaxxer.hikari.HikariConfig.setDriverClassName(HikariConfig.java:501)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.zaxxer.hikari.util.PropertyElf.setProperty(PropertyElf.java:146)at com.zaxxer.hikari.util.PropertyElf.lambda$setTargetFromProperties$0(PropertyElf.java:57)at com.zaxxer.hikari.util.PropertyElf$$Lambda$587/493239805.accept(Unknown Source)at java.util.Hashtable.forEach(Hashtable.java:879)-  locked cn.hutool.setting.dialect.Props@647b312dat com.zaxxer.hikari.util.PropertyElf.setTargetFromProperties(PropertyElf.java:52)at com.zaxxer.hikari.HikariConfig.<init>(HikariConfig.java:134)at cn.hutool.db.ds.hikari.HikariDSFactory.createDataSource(HikariDSFactory.java:57)at cn.hutool.db.ds.AbstractDSFactory.createDataSource(AbstractDSFactory.java:127)at cn.hutool.db.ds.AbstractDSFactory.getDataSource(AbstractDSFactory.java:92)-  locked cn.hutool.db.ds.hikari.HikariDSFactory@2be25459[arthas@22366]$ thread --state RUNNABLE
Threads Total: 29, NEW: 0, RUNNABLE: 7, BLOCKED: 1, WAITING: 11, TIMED_WAITING: 10, TERMINATED: 0
ID              NAME                                           GROUP                          PRIORITY        STATE          %CPU            TIME            INTERRUPTED    DAEMON
49              as-command-execute-daemon                      system                         10              RUNNABLE       100             0:0             false          true
36              Attach Listener                                system                         9               RUNNABLE       0               0:0             false          true
5               Signal Dispatcher                              system                         9               RUNNABLE       0               0:0             false          true
1               main                                           main                           5               RUNNABLE       0               0:15            false          false
39              nioEventLoopGroup-2-1                          system                         10              RUNNABLE       0               0:0             false          false
44              nioEventLoopGroup-2-2                          system                         10              RUNNABLE       0               0:0             false          false
40              nioEventLoopGroup-3-1                          system                         10              RUNNABLE       0               0:0             false          false
Affect(row-cnt:0) cost in 103 ms.[arthas@22366]$ thread 1
"main" Id=1 RUNNABLEat java.sql.DriverManager.registerDriver(DriverManager.java:358)-  locked java.lang.Class@5a6f639cat java.sql.DriverManager.registerDriver(DriverManager.java:334)-  locked java.lang.Class@5a6f639cat com.sybase.jdbc4.jdbc.SybDriver.registerWithDriverManager(SybDriver.java:708)-  locked java.lang.Class@5a6f639cat com.sybase.jdbc4.jdbc.SybDriver.<init>(SybDriver.java:139)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at java.lang.Class.newInstance(Class.java:442)at com.zaxxer.hikari.HikariConfig.setDriverClassName(HikariConfig.java:501)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.zaxxer.hikari.util.PropertyElf.setProperty(PropertyElf.java:146)at com.zaxxer.hikari.util.PropertyElf.lambda$setTargetFromProperties$0(PropertyElf.java:57)at com.zaxxer.hikari.util.PropertyElf$$Lambda$587/493239805.accept(Unknown Source)at java.util.Hashtable.forEach(Hashtable.java:879)-  locked cn.hutool.setting.dialect.Props@657e32f4at com.zaxxer.hikari.util.PropertyElf.setTargetFromProperties(PropertyElf.java:52)at com.zaxxer.hikari.HikariConfig.<init>(HikariConfig.java:134)at cn.hutool.db.ds.hikari.HikariDSFactory.createDataSource(HikariDSFactory.java:57)at cn.hutool.db.ds.AbstractDSFactory.createDataSource(AbstractDSFactory.java:127)at cn.hutool.db.ds.AbstractDSFactory.getDataSource(AbstractDSFactory.java:92)-  locked cn.hutool.db.ds.hikari.HikariDSFactory@69e98e1fat cn.hutool.db.ds.DSFactory.get(DSFactory.java:111)at cn.hutool.db.Db.use(Db.java:44)

从上面的命令结果可以看出,是有线程陷入死锁了,导致了程序没办法继续往下执行。

那么,现在问题来了,是什么原因导致死锁的发生。我们这里要先讲一个理论,关于类初始化加锁场景:

同时使用相同的类或接口。还有一种可能性是,类或接口的初始化可以作为该类或接口初始化的一部分递归地请求;例如,类a中的变量初始值设定项可以调用不相关类B的方法,而不相关类B又可以调用类a的方法。Java虚拟机的实现负责使用以下过程进行同步和递归初始化。
该过程假设类对象已经过验证和准备,并且类对象包含表示以下四种情况之一的状态:
1. 该类对象已验证并准备好,但尚未初始化。
2. 这个类对象正被某个特定的线程T初始化。
3. 该类对象已完全初始化并可以使用。
4. 此类对象处于错误状态,可能是因为尝试初始化但失败。

对于每个类或接口C,都有一个唯一的初始化锁LC。从C到LC的映射由Java虚拟机实现决定。初始化C的过程如下:
1. 同步C的初始化锁LC。这包括等待当前线程可以获取LC。
2. 如果C的类对象指示其他线程正在对C进行初始化,则释放LC并阻止当前线程,直到通知正在进行的初始化已完成,此时重复此步骤。
3. 如果C的类对象指示当前线程正在对C进行初始化,那么这必须是一个递归的初始化请求。释放LC并正常完成。
4. 如果C的类对象指示C已经初始化,则不需要进一步的操作。释放LC并正常完成。
5. 如果C的类对象处于错误状态,则无法进行初始化。释放LC并抛出NoClassDefFoundError。
6. 否则,记录当前线程正在初始化C的类对象,然后释放LC。 然后,初始化值为编译时常量表达式的接口的最终类变量和字段

我们这里可以理一下问题发生的原因:

  1. 线程29 要进行数据库链接初始化,而该数据库是Oracle数据库。在进行初始化的时候,获取了DriverManager实例,这个时候因为DriverManager未初始化,故进行了DriverManager静态代码块的初始化,我们可以看上面的线程调用链:

        at java.sql.DriverManager.loadInitialDrivers(DriverManager.java:583)at java.sql.DriverManager.<clinit>(DriverManager.java:101)at oracle.jdbc.driver.OracleDriver.<clinit>(OracleDriver.java:188)
    

    java.sql.DriverManager.loadInitialDrivers函数会找出classpath下所有的jdbc驱动实现类。

  2. 线程1 在开始进行Sybase数据库链接的创建,在调用的时候,需要对DriverManager.class进行了加锁。而此时因为DriverManager处于初始化过程,还未初始化完毕,故程序暂停于此,等待其他线程通知该类初始化完毕。代码如下:

    protected void registerWithDriverManager() {try {Class var1 = DriverManager.class;synchronized(DriverManager.class) {DriverManager.registerDriver(this);Enumeration var2 = DriverManager.getDrivers();while(var2.hasMoreElements()) {Driver var3 = (Driver)var2.nextElement();if (var3 instanceof com.sybase.jdbcx.SybDriver && var3 != this) {DriverManager.deregisterDriver(var3);}}}} catch (SQLException var6) {}
    }
    
  3. 而第一步的线程29需要将全部的驱动类加载进去,这个时候还没有将全部驱动类加载完毕,正在加载com.microsoft.sqlserver.jdbc.SQLServerDriver。而这个类加载过程中,需要调用方法DriverManager.registerDriver(new SQLServerDriver());,查看源码,可以知道该方法是需要被加锁的。而因为第二步DriverManager被加锁了,并因为DriverManager未初始化完毕导致锁未能释放。故陷入了两边都拿了对应的锁,这就形成了死锁的情况!!!

解决方案

不要用并发的形式进行JDBC驱动类的加载。也可以用取巧的方式,延迟一个线程中关于数据库的加载。这样就可以很大程度地避免该问题的发生。

结果

死锁问题得到解决,程序正常运行!!!

总结

从点到面,可以学到很多东西。知其然,知其所以然,才能不断地进步!!!

扩展

类初始化官网说明

随缘求赞

如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以点击关注
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!

问题解决:使用arthas发现JDBC驱动类死锁阻塞问题并加以解决的过程相关推荐

  1. 使用jdbc驱动连接mysql_使用jdbc连接mysql数据库

    1.提供mysql的jdbc驱动(我的博客文件里提供了驱动jar包) 2.使用IDEA工具,把jar包添加到项目里(具体步骤如下) 1)打开模块设置 2)选择libraries功能,点击+号,选择ja ...

  2. Hibernate的几个关键类的详解及Hibernate的运行过程

    Configuration 类 Configuration 类负责管理 Hibernate 的配置信息.包括如下内容: Hibernate运行的底层信息:数据库的URL.用户名.密码.JDBC驱动类, ...

  3. jdbc版本低MySQL版本高_Mysql JDBC驱动版本与Mysql版本的对应问题解决

    好长时间不用Mysql了, 昨天朋友有一个小项目在我的机器上跑的一点问题都没有, 到他的机器上却是报服务器内部错误(500), 用QQ上远程协助(太慢 好长时间不用Mysql了, 昨天朋友有一个小项目 ...

  4. 配置好某个版本的驱动类之后运行程序出现以下报错:UnsupportedClassVersionError: com/mysql/jdbc/Driver : Unsupported major.min

    一.若jdk版本足够高,则看这里: 出现报错的原因: 安装的数据库版本与导入配置的驱动类版本不适配,因此出现该报错. 解决方法: 查看你下载的数据库的版本,然后去下载一个适配的驱动类来为JAVA工程配 ...

  5. java jdbc工具类抽取_JavaWeb入门(三):JDBC工具类的抽取

    一.通过上篇文章,我们已经可以使用JDBC对数据库中的表进行增删改查啦(JDBC的基本使用:https://www.cnblogs.com/Infancy/p/12499806.html),我们对上篇 ...

  6. jdbc驱动_JDBC概述和CRUD

    第八章 JDBC的简介 8.1 简介 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问 ...

  7. jsp mysql驱动程序_JSP通过JDBC驱动MySQL数据库方法

    JSP通过JDBC驱动MySQL数据库方法 发布时间:2020-03-26 15:42 百度谷歌一翻后,发现jsp要连mysql数据库的话,有这样的一种方法:使用jsp通过JDBC驱动链接MySQL数 ...

  8. JDBC学习笔记01【JDBC快速入门、JDBC各个类详解、JDBC之CRUD练习】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  9. db2 jdbc驱动参数_JDBC详细整理(一)

    一.什么是JDBC JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库.原来我们操作数据库是在控制台使用SQL语句来操作数据库 ...

最新文章

  1. 动态规划-最优二叉查找树
  2. SAP MM 对采购订单执行收货,报错 - Table T169P entry ZNMI does not exist -
  3. ArcGIS中标注之一上下标、分数等特殊形式标注(转)
  4. pytho sin(1/x)震荡间断点
  5. NHibernate部分错误
  6. 算法全覆盖,还能玩星际争霸,开源决策智能平台OpenDILab面世
  7. Leecode01. 两数之和——Leecode大厂热题100道系列
  8. Java面试题2020,单击更改以将java安装到其他文件夹
  9. 第61课 查分程序 《小学生C++趣味编程》
  10. ext/iconv/.libs/iconv.o: In function `_php_iconv_strlen'
  11. 静态成员内部类和非静态成员内部类的实例化方式
  12. C.Fountains(Playrix Codescapes Cup (Codeforces Round #413, rated, Div. 1 + Div. 2)+线段树+RMQ)...
  13. Python学习第一弹——Python环境搭建
  14. 二进制转8421bcd码_绝对值编码器当中的格雷码
  15. 青鸟BCNT-网络信息安全工程师
  16. Oracle字符集及其查看和修改
  17. 基于移动通信数据的城市可视分析研究
  18. QQ桌球瞄准器开发(6)(7) 完结篇
  19. 游戏逆向 修改植物大战僵尸阳光值
  20. office快捷键设置

热门文章

  1. 测试周周三工作分配报告——PM(李忠)
  2. 我实习时参与过的某医院信息系统功能说明
  3. SpringBoot系统搭建集成-007-集成Redis
  4. java 8精简jre_精简压缩jre
  5. 技术干货 | 基于MindSpore的图算融合探索和实践
  6. OAuth 2.0 学习
  7. 当前行情下,真的还能“跳进”进大厂吗?
  8. Python—实现本地音乐播放器(添加/播放/暂停/下一首/上一首/音量/打开超链接)
  9. MATLAB神经网络学习笔记之:对线性神经网络进行自适应训练
  10. 输入有限个英文(小写)单词,单词可以重复(不统计数量),按照降序输出这些单词。