問題解決:arthasを使用してJDBCドライバークラスのデッドロックブロックの問題を見つけて解決するプロセス

問題シナリオ

マイクロサービスプロジェクトを開発しているときに、データベースリンクの作成プロセスがブロック状態になっていることがわかりました。症状は次のとおりです。プログラムがログを出力した後、プログラムはスタックし、新しいログを表示しなくなります。したがってarthas、問題追跡に使用し、見つかった問題に基づいて、ターゲットを絞った解決策を見つけてください。

問題のある環境

ソフトウェア バージョン
JDK 1.8
スプリングブーツ 2.1.1。リリース
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=1
    at java.sql.DriverManager.registerDriver(DriverManager.java:334)
    -  blocked on java.lang.Class@5a6f639c
    at 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@647b312d
    at 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 RUNNABLE
    at java.sql.DriverManager.registerDriver(DriverManager.java:358)
    -  locked java.lang.Class@5a6f639c
    at java.sql.DriverManager.registerDriver(DriverManager.java:334)
    -  locked java.lang.Class@5a6f639c
    at com.sybase.jdbc4.jdbc.SybDriver.registerWithDriverManager(SybDriver.java:708)
    -  locked java.lang.Class@5a6f639c
    at 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@657e32f4
    at 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@69e98e1f
    at cn.hutool.db.ds.DSFactory.get(DSFactory.java:111)
    at cn.hutool.db.Db.use(Db.java:44)

上記のコマンドの結果から、スレッドがトラップ死锁され、プログラムが実行を継続できなくなっていることがわかります。

だから、今問題はここにあります、それが死锁起こった原因は何ですか?まず、理論について类初始化加锁シーンについて説明ます。

同じクラスまたはインターフェースを同時に使用します。クラスまたはインターフェイスの初期化は、クラスまたはインターフェイスの初期化の一部として再帰的に要求される可能性もあります。たとえば、クラスaの変数初期化子は、無関係のクラスBのメソッドを呼び出すことができますが、無関係です。クラスBはクラスaのメソッドを呼び出すことができます。Java仮想マシンの実装は、次の手順を使用した同期と再帰的初期化を担当します。
このプロセスは、クラスオブジェクトが検証および準備され、クラスオブジェクトに次の4つの状況のいずれかを表す状態が含まれていることを前提としてい
ます。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この関数は、クラスパスの下にあるすべてのjdbcドライバー実装クラスを検索します。

  2. スレッド1Sybaseはデータベースリンクの作成を開始し、呼び出されたときに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());、ソースコードを確認する必要があります。これにより、メソッドをロックする必要があることがわかります。また、2番目のステップDriverManagerがロックDriverManagerされていて、初期化が完了していなかったためにロックを解除できなかったためです。それで、私は両側で対応するロックを取得する死锁状況になりました

解決

コンカレントフォームを使用しJDBCてドライバークラスロードしないでください巧妙な方法を使用して、スレッドへのデータベースのロードを遅らせることもできます。このようにして、問題を大幅に回避することができます。

結果

デッドロックの問題が解決され、プログラムは正常に実行されます。

総括する

ポイントからサーフェスまで、多くのことを学ぶことができます。理由を知り、理由を知ることによってのみ、私たちは進歩を続けることができます!

展開

クラス初期化公式ウェブサイトの説明

賞賛を求める

私の記事がすべての人に役立つ場合は、記事の下部にある[いいね]または[お気に入り]をクリックできます。
良いディスカッションがある場合はメッセージを残すことができます。
今後の記事を引き続き表示する場合は、[フォロー
する]をクリックしてください。次のQRコードをスキャンして、私の公開アカウントをフォローできます:Fengye Zhixuege、私の最新の共有をチェックしてください!
ここに画像の説明を挿入します
バイバイ

おすすめ

転載: blog.csdn.net/u013084266/article/details/112535441