logbackで使用されるデーモンスレッド
私はJavaアプリケーションでの問題についてお話しましょう、非同期のアペンダは、どのようにメインスレッドの終わりにされlogback停止に来ましたの?
リプレイ
私がしていたlogback
テストケースと、このコードと書いたlogback
コンフィギュレーションを:
// 一个测试类,main函数中简单的打印了几行日志
public class Test {
private static final Logger LOGGER = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
LOGGER.info("test log 1");
LOGGER.info("test log 2");
}
}
これは私が使用するものであるlogback
構成をされてroot-logger
2で構成されappender
、1 ConsoleAppender
コンソールに出力の内容を記録します、と他のがに設定されている、それは、ログファイル出力の内容に非同期方式を使用していますAsyncAppender
FileAppender
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/usr/local/test.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<root level="debug">
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNC"/>
</root>
</configuration>
私は正常に行われた場合Test.main()
、ウォッチコンソール出力ファイルは、通常のログです。その後、観察するためにAsyncAppender
原則を、私は午前中にAsyncAppender
、親クラスAsyncAppenderBase
の一般的な原則を見て、中:呼び出されるメソッドは、実際には、私がスレッドを開始しました。インターセプト法より重要なコードはであるキューをブロックから取得したサイクル、私は具体的な希望にここにブレークポイント、追撃を果たし、オーバー見てAsyncAppenderBase
start()
worker.start()
Worker.run()
while
ILoggerEvent
Appender
while (parent.isStarted()) {
try {
E e = parent.blockingQueue.take();
// 这里打了断点
aai.appendLoopOnAppenders(e);
} catch (InterruptedException ie) {
break;
}
}
ブレークポイントに到達すると、Javaアプリケーションが終わった全体突然見つけ、ステッパーをクリックして、しばらくの変数のために観察します。いずれかの例外が発生しなければ。私は必ずしもブレークポイントで終わらない、この場合に多くの時間を再試行して、可能性ダウンいくつかの手順を、しかし、デバッグモードでは、Javaアプリケーションは、いくつかの点での兆候が存在しないだろう「正常終了」は。
私は、メインスレッドがオーバー実行しなければならないことを示す、ログの2行がプリントアウトされたビットコンソールを確認しなければならなかったが、私は知識ベースが持っていた子スレッドが終了していない場合、それは子スレッドを待ちます、Javaのメインスレッドの終わりに後、JVMは終了タスクを実行します。(ここで私はデーモンスレッドの概念を覚えていません)
!!!上記の結論は間違っています
それまでに望んでいたjstack
とき、それを観察するためにmain-Thread
:スレッドの終了後に最終的に状況は何です
私たちは、ここで見つけます:
DestroyJavaVM
で、実際にスレッドRUNNABLE
段階だけでなく、サブスレッドの実行中に、ああ、なぜそれが開始
疑い別の表情でAsyncAppender-Worker-ASYNC
も非同期ログ印刷ジョブスレッド、及びあるスレッド、RUNNABLE
それがあると思われる状態、守护线程(daemon)
Javaスレッドの基本それを考える、ユーザスレッドとスレッドガード、から直接ここに掲載Thread
のsetDaemon
仕方コードのコメントは、言った:ユーザスレッドやデーモンスレッドとして、このスレッドをマークし、唯一の現在実行中のスレッド、すべての時間のデーモンスレッドでJVMは、終了します。
見てください方法:AsyncAppenderBase
start()
我々は、それが、見ることができるworker
ために指定されているdaemon
実際には、ここでの問題は解決されるだろう、スレッド。
結論
複雑ではありません遭遇する問題は、問題は主に知識ベースであります
デーモン・スレッドのみならば、;ジャワ、能力上のユーザスレッドとスレッドガードをマルチスレッドと違いはありません、最も重要な違いは、生き残ったユーザスレッドがある場合と、JVMが終了すると、終了していないということですJVMは、すべてのデーモンスレッドを殺す、そして終了します。
PS:
誰がどのくらいI DEBUGを知っています。。。ただ、理解の範囲を超えました!!!ほとんどそれは形而上学だと思いました