Java デーモン スレッドの理解と応用

Java には、ユーザー スレッド (ユーザー スレッド) とデーモン スレッド (デーモン スレッド) の 2 種類のスレッドがあります。
ユーザー スレッドは理解しやすいため、私たちが日々の開発で作成するビジネス ロジック コードはユーザー スレッドで実行されます。デーモン スレッドについては特別な理解が必要です。

1.1 デーモンスレッドとは何ですか?

オペレーティング システムにはデーモン スレッドの概念はなく、デーモン プロセスのみが存在します。しかし、Java 言語のメカニズムは JVM に基づいて構築されており、このメカニズムは Java プラットフォームがオペレーティング システムの最下位層を保護することを意味し、Java プラットフォームは独自の仮想プラットフォーム内で自身にとって有益なメカニズムを構築できます。Java 言語またはプラットフォームの設計者は Unix オペレーティング システムの考え方に多かれ少なかれ影響を受けており、デーモン スレッドのメカニズムが JVM などのプラットフォームに適応されたため、デーモン スレッドが誕生しました。

いわゆるデーモン スレッドとは、プログラムの実行中にバックグラウンドで一般的なサービスを提供するスレッドを指します。たとえば、ガベージ コレクション スレッドは非常に有能なガーディアンですが、このスレッドはプログラムに不可欠な部分ではありません。したがって、すべての非デーモン スレッドが終了すると、プログラムは終了し、プロセス内のすべてのデーモン スレッドが強制終了されます。逆に、デーモン以外のスレッドが実行されている限り、プログラムは終了しません。

実際、ユーザー スレッド (ユーザー スレッド) とデーモン スレッド (デーモン スレッド) の間には本質的に違いはありません。唯一の違いは、仮想マシンの終了にあります。すべてのユーザー スレッドが終了すると、デーモン スレッドだけが残ります。スレッドが存在し、仮想マシンが終了します。ガーディアンがなければデーモン スレッドは何もする必要がなく、プログラムを実行し続ける必要がないからです。

1.2 デーモンスレッドの使用方法と注意事項

デーモンスレッドは仮想マシン内に提供されるだけでなく、ユーザーが手動でユーザースレッドをデーモンスレッドに設定・変換することも可能です。

Threadクラスには、通常のスレッド(ユーザースレッド)をデーモンスレッドとして設定するためのsetDaemon(true)メソッドが用意されています。

public final void setDaemon(boolean on);

使用中に注意すべき点がいくつかあります。
1.thread.setDaemon(true) は thread.start() の前に設定する必要があります。設定しないと、IllegalThreadStateException がスローされます。これは、実行中の通常のスレッドをデーモン スレッドとして設定できないことも意味します。これは、オペレーティング システムのデーモン プロセスとは明らかに異なります。デーモン プロセスが作成された後、プロセスは元のセッションの制御を取り除くことができます + プロセスに元のプロセス グループの制御を取り除くことができます +プロセスは元の制御端末の制御を取り除き、仮想マシンの言語メカニズムはシステムレベルの言語とは本質的に異なります。

2. デーモンスレッド内で生成された新規スレッドもデーモンに属します。この点がオペレーティングシステムのデーモンプロセスとは根本的に異なり、デーモンプロセスfork()から派生した子プロセスはデーモンプロセスではなくなり、親プロセスのプロセス関連情報をコピーしますが、そのプロセスはデーモンプロセスではなくなります。子プロセス 親プロセスは init プロセスではありません。いわゆるデーモン プロセスとは、基本的に、親プロセスが終了すると、init がプロセスを採用し、ファイル 0、1、および 2 はすべて /dev/null になり、現在のディレクトリは / です。

3. すべてのアプリケーションを、読み取りおよび書き込み操作や計算ロジックなどのサービスのデーモン スレッドに割り当てることができるわけではありません。この種のアプリケーションは、デーモン スレッドが動作する前に仮想マシンを終了している可能性があるためです。これは、デーモン スレッドがいつでも (操作の途中であっても) 中断される可能性があるため、デーモン スレッドがファイルやデータベースなどの固有のリソースにアクセスしてはいけないことも意味します。

以下は、ファイル出力を完了するデーモン スレッド タスクの例です。

import java.io.*;  

class TestRunnable implements Runnable {
    
    
    public void run(){
    
    
        try {
    
    
            Thread.sleep(1000); // 守护线程阻塞1秒后运行  
            File f = new File("daemon.txt");
            FileOutputStream os = new FileOutputStream(f,true);
            os.write("daemon".getBytes());
        } catch(IOException e1) {
    
      
            e1.printStackTrace();  
        } catch(InterruptedException e2) {
    
      
            e2.printStackTrace();  
        }  
    }  
}  

public class TestDemo2 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Runnable tr = new TestRunnable();
        Thread thread = new Thread(tr);
        thread.setDaemon(true); // 设置守护线程(必须在thread.start()之前)
        thread.start(); // 开始执行分进程
    }
}

上記のコードを実行した結果、ファイル daemon.txt にデーモン文字列が存在しません。
ただし、コードの thread.setDaemon(true); 行をコメント アウトすると、現時点ではスレッドが通常のユーザー スレッドであるため、ファイル daemon.txt をデーモン文字列に書き込むことができます。
簡単に理解すると、JRE がプログラムの実行を終了したかどうかを判断する基準は、バックグラウンド スレッド (デーモン スレッド) の状態に関係なく、すべてのフォアグラウンド スレッド (ユーザー スレッド) が実行を完了したことです。

1.3 デーモンスレッドの適用シナリオ

ここまで述べてきましたが、デーモン スレッドの実際の用途は何でしょうか? たとえば、Web サーバーのサーブレットがコンテナを開始すると、サービス スレッド、つまりスケジューリング スレッドがバックグラウンドで初期化され、http リクエストの処理を担当します。その後、リクエストごとに、スケジューリング スレッドはスレッド プールからワーカー スレッドを取り出し、同時実行制御の目的を達成するためにリクエストを処理します。つまり、スケジュールされたスレッドは実際には Java のスレッド プールで使用されます。

1.4 概要

私の理解では、デーモン スレッドは、スレッドが低レベルのスレッドであることを JVM に伝えるために使用され、終了する前に実行が完了するのを待つ必要はありません。JVM は、このスレッドに関係なく、いつでも終了できます。 。
日常のビジネス関連の CRUD 開発では、デーモン スレッドの概念は実際には注目されず、使用されることもほとんどありません。
しかし、さらに上を目指したい場合は、いくつかのフレームワークの基礎となる実装など、これらの深い概念を理解する必要があります。

おすすめ

転載: blog.csdn.net/liufang_imei/article/details/132712550