問題シナリオ
マイクロサービスプロジェクトを開発しているときに、データベースリンクの作成プロセスがブロック状態になっていることがわかりました。症状は次のとおりです。プログラムがログを出力した後、プログラムはスタックし、新しいログを表示しなくなります。したがって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を解放します。次に、コンパイル時に初期値が定数式であるインターフェイスの最終クラス変数とフィールドを初期化します。
ここで、問題の原因に対処できます。
-
スレッド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ドライバー実装クラスを検索します。 -
スレッド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) { } }
-
最初のステップのスレッド29は、すべてのドライバークラスをロードする必要があります。この時点では、すべてのドライバークラスはまだロードされておらず、ロードされてい
com.microsoft.sqlserver.jdbc.SQLServerDriver
ます。このクラスをロードするプロセスでは、メソッドを呼び出しDriverManager.registerDriver(new SQLServerDriver());
、ソースコードを確認する必要があります。これにより、メソッドをロックする必要があることがわかります。また、2番目のステップDriverManager
がロックDriverManager
されていて、初期化が完了していなかったためにロックを解除できなかったためです。それで、私は両側で対応するロックを取得する死锁
状況になりました!!!
解決
コンカレントフォームを使用しJDBC
てドライバークラスをロードしないでください。巧妙な方法を使用して、スレッドへのデータベースのロードを遅らせることもできます。このようにして、問題を大幅に回避することができます。
結果
デッドロックの問題が解決され、プログラムは正常に実行されます。!!
総括する
ポイントからサーフェスまで、多くのことを学ぶことができます。理由を知り、理由を知ることによってのみ、私たちは進歩を続けることができます!!!
展開
賞賛を求める
私の記事がすべての人に役立つ場合は、記事の下部にある[いいね]または[お気に入り]をクリックできます。
良いディスカッションがある場合はメッセージを残すことができます。
今後の記事を引き続き表示する場合は、[フォロー
する]をクリックしてください。次のQRコードをスキャンして、私の公開アカウントをフォローできます:Fengye Zhixuege、私の最新の共有をチェックしてください!