Java 言語では、スレッドであってもスレッド プールであっても、デフォルトはユーザー スレッドです。 したがって、ユーザー スレッドは通常のスレッドとも呼ばれます。
スレッドを例に挙げます。スレッドがデーモン スレッドであるかどうかを確認したい場合は、isDaemon()
メソッドを呼び出してクエリを実行するだけです。クエリ値が # の場合は、 ##false の場合、これはデーモン スレッドではないことを意味するため、当然ユーザー スレッドに属します。
次のコードが表示されます:
public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("我是子线程"); } }); System.out.println("子线程==守护线程:" + thread.isDaemon()); System.out.println("主线程==守护线程:" + Thread.currentThread().isDaemon()); }
上記のプログラムの実行結果は次のとおりです。
上記の結果からわかるように、デフォルトでは、メインスレッドと作成された新しいスレッドは両方ともユーザー スレッドです。
PS: Thread.currentThread() は、現在のコードを実行しているスレッド インスタンスを取得することを意味します。2. 積極的にデーモン スレッドに変更します
デーモンスレッドの役割は「ウェイター」のようなもので、ユーザースレッドの役割は「顧客」のようなもので、すべての「顧客」が退場すると(すべての実行が終了すると)、「ウェイター」は(デーモンスレッド) も存在意味がないため、プログラム内のすべてのユーザースレッドが実行を終了すると、デーモンスレッドがまだ動作しているかどうかに関係なく、ユーザースレッドとともに終了し、プログラム全体も終了します。ランニングを終了します。
デフォルトのユーザー スレッドをデーモン スレッドに変更するにはどうすればよいですか?この質問には 2 つの状況で回答する必要があります。まず、スレッドの場合は、setDaemon(true) を設定することで、ユーザー スレッドをデーモン スレッドに直接変更できます。メソッドを作成し、スレッド プールの場合は
ThreadFactory を使用してスレッド プール内の各スレッドをデーモン スレッドにする必要があります。次に、これを個別に実装します。 2.1 スレッドをデーモン スレッドとして設定する
スレッドを使用している場合は、
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:java;"> public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是子线程");
}
});
// 设置子线程为守护线程
thread.setDaemon(true);
System.out.println("子线程==守护线程:" + thread.isDaemon());
System.out.println("主线程==守护线程:" + Thread.currentThread().isDaemon());
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
上記プログラムの実行結果は次のとおりです:
2.2スレッド プールをデーモン スレッドとして設定する
スレッド プールをデーモン スレッドとして設定するのは比較的面倒です。スレッド プール内のすべてのスレッドをデーモン スレッドとして設定する必要があります。このとき、
ThreadFactory// 创建固定个数的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(10, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); // 设置线程为守护线程 t.setDaemon(false); return t; } });
次の図に示すように:
上の図に示すように、私が作成したプログラム全体には 10 個のデーモン スレッドがあることがわかります。スレッド プールを作成するための他のいくつかの設定も同様であり、これらはすべて
ThreadFactory を通じて均一に設定されるため、ここでは 1 つずつリストしません。
3. デーモン スレッド VS ユーザー スレッドこれまでの学習により、2 つの異なるスレッド タイプを作成できます。次に、小さな例を使用して見てみましょう。
ループを実行し、毎回合計 10 回情報を出力します。 100 ミリ秒スリープして、プログラムの実行結果を観察します。
3.1 ユーザー スレッド新しく作成されたスレッドはデフォルトでユーザー スレッドとなるため、スレッドに対して特別な処理を実行する必要はありません。
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:java;">/**
* Author:Java中文社群
*/
public class DaemonExample {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
// 打印 i 信息
System.out.println("i:" + i);
try {
// 休眠 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 启动线程
thread.start();
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
上記プログラムの実行結果は次のとおりです。
上記の結果から、プログラムが 10 回印刷を実行するまでプロセスは正常に終了しないことがわかります。
3.2 デーモン スレッド
/** * Author:Java中文社群 */ public class DaemonExample { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 10; i++) { // 打印 i 信息 System.out.println("i:" + i); try { // 休眠 100 毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }); // 设置为守护线程 thread.setDaemon(true); // 启动线程 thread.start(); } }
ご覧のとおり上記の結果から、スレッドがデーモン スレッドとして設定されている場合、プログラム全体は、デーモン スレッド
for が 10 回循環してから終了するのを待たずに、メイン スレッドが終了すると、デーモン スレッドが終了します。サイクルを 1 回だけ実行して終了する これは、デーモン スレッドとユーザー スレッドの違いを示しています。
守护线程是为用户线程服务的,当一个程序中的所有用户线程都执行完成之后程序就会结束运行,程序结束运行时不会管守护线程是否正在运行,由此我们可以看出守护线程在 Java 体系中权重是比较低的。
守护线程的使用需要注意以下三个问题:
守护线程的设置 setDaemon(true)
必须要放在线程的 start()
之前,否则程序会报错。
在守护线程中创建的所有子线程都是守护线程。
使用 jojn()
方法会等待一个线程执行完,无论此线程是用户线程还是守护线程。
接下来我们分别演示一下,以上的注意事项。
当我们将 setDaemon(true)
设置在 start()
之后,如下代码所示:
public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 10; i++) { // 打印 i 信息 System.out.println("i:" + i + ",isDaemon:" + Thread.currentThread().isDaemon()); try { // 休眠 100 毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }); // 启动线程 thread.start(); // 设置为守护线程 thread.setDaemon(true); }
以上程序执行结果如下:
从上述结果可以看出,当我们将 setDaemon(true)
设置在 start()
之后,不但程序的执行会报错,而且设置的守护线程也不会生效。
public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { Thread thread2 = new Thread(new Runnable() { @Override public void run() { } }); System.out.println("守护线程的子线程 thread2 isDaemon:" + thread2.isDaemon()); } }); // 设置为守护线程 thread.setDaemon(true); // 启动线程 thread.start(); Thread.sleep(1000); }
以上程序执行结果如下:
从上述结果可以看出,守护线程中创建的子线程,默认情况下也属于守护线程。
通过 3.2 部分的内容我们可以看出,默认情况下程序结束并不会等待守护线程执行完,而当我们调用线程的等待方法 join()
时,执行的结果就会和 3.2 的结果有所不同,下面我们一起来看吧,
示例代码如下:
public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 10; i++) { // 打印 i 信息 System.out.println("i:" + i); try { // 休眠 100 毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }); // 设置为守护线程 thread.setDaemon(true); // 启动线程 thread.start(); // 等待线程执行完 thread.join(); System.out.println("子线程==守护线程:" + thread.isDaemon()); System.out.println("主线程==守护线程:" + Thread.currentThread().isDaemon()); }
以上程序执行结果如下:
通过上述结果我们可以看出,即使是守护线程,当程序中调用 join()
方法时,程序依然会等待守护线程执行完成之后再结束进程。
守护线程的典型应用场景就是垃圾回收线程,当然还有一些场景也非常适合使用守护线程,比如服务器端的健康检测功能,对于一个服务器来说健康检测功能属于非核心非主流的服务业务,像这种为了主要业务服务的业务功能就非常合适使用守护线程,当程序中的主要业务都执行完成之后,服务业务也会跟随者一起销毁。
首先来说,线程的类型(用户线程或守护线程)并不影响线程执行的优先级,如下代码所示,定义一个用户线程和守护线程,分别执行 10 万次循环,通过观察最后的打印结果来确认线程类型对程序执行优先级的影响。
public class DaemonExample { private static final int count = 100000; public static void main(String[] args) throws InterruptedException { // 定义任务 Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i < count; i++) { System.out.println("执行线程:" + Thread.currentThread().getName()); } } }; // 创建守护线程 t1 Thread t1 = new Thread(runnable, "t1"); // 设置为守护线程 t1.setDaemon(true); // 启动线程 t1.start(); // 创建用户线程 t2 Thread t2 = new Thread(runnable, "t2"); // 启动线程 t2.start(); } }
以上程序执行结果如下:
通过上述结果可以看出,线程的类型不管是守护线程还是用户线程对程序执行的优先级是没有任何影响的,而当我们将 t2
的优先级调整为最大时,整个程序的运行结果就完全不同了,
如下代码所示:
public class DaemonExample { private static final int count = 100000; public static void main(String[] args) throws InterruptedException { // 定义任务 Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0; i < count; i++) { System.out.println("执行线程:" + Thread.currentThread().getName()); } } }; // 创建守护线程 t1 Thread t1 = new Thread(runnable, "t1"); // 设置为守护线程 t1.setDaemon(true); // 启动线程 t1.start(); // 创建用户线程 t2 Thread t2 = new Thread(runnable, "t2"); // 设置 t2 的优先级为最高 t2.setPriority(Thread.MAX_PRIORITY); // 启动线程 t2.start(); } }
以上程序执行结果如下:
00000000 通过上述的结果可以看出,程序的类型和程序执行的优先级是没有任何关系,当新创建的线程默认的优先级都是 5 时,无论是守护线程还是用户线程,它们执行的优先级都是相同的,当将二者的优先级设置不同时,执行的结果也会随之改变(优先级设置的越高,最早被执行的概率也越大)。
以上がJava でユーザー スレッドとデーモン スレッドを使用する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。