java守护线程和普通线程的区别,守护线程和用户线程区别

  java守护线程和普通线程的区别,守护线程和用户线程区别

  00-1010 1.默认用户线程2。主动修改守护线程2.1设置线程为守护线程2.2设置线程池为守护线程3。守护线程VS用户线程3.1用户线程3.2守护线程3.3总结4。守护线程的注意事项4.1守护线程的执行顺序4.2子线程4.3 join和守护线程5。守护线程6的应用场景。守护线程7的执行优先级。总结前言;

  在 Java 语言中线程分为两类:用户线程和守护线程,但是很少有人知道它们之间的区别,所以本文格雷带你看看它们之间的区别以及守护线程的一些注意事项。

  00-1010Java 语言中无论是线程还是线程池,默认都是用户线程,所以用户线程也变成了正常线程。

  以螺纹为例。如果要检查一个线程是否是守护线程,只需要调用isDaemon()方法进行查询。如果查询的值为false,则意味着它不是守护线程,因此它自然属于用户线程。

  如下代码所示:

  public static void main(string[]args)抛出中断异常{ thread thread=new thread(new runnable(){ @ override public void run(){ system . out . println(我是子线程));} });system . out . println( child thread==daemon thread: thread . isdaemon());System.out.println(主线程==守护线程: thread.currentthread()。is demon());}以上程序的执行结果为:

  从以上结果可以看出,默认情况下主线程和创建的新线程都为用户线程.

  Ps: thread.currentthread()的意思是获取执行当前代码的线程实例。

  00-1010守护线程也叫后台线程或服务线程,守护线程是为用户线程服务的.当程序中的所有用户线程执行完毕后,守护线程也会跟着结束。

  守护线程的角色就像服务员,而用户线程的角色就像顾客。当所有的客户都走了(所有的执行都结束了),waiter(守护线程)就没有任何意义了。因此,当一个程序中的所有用户线程执行完毕后,不管守护线程是否还在工作,它都会随着用户线程结束,整个程序也会相应地结束运行。

  那如何将默认的用户线程修改为守护线程呢?

  这个问题要分两种情况来回答。第一,如果是线程,可以通过设置setDaemon(true)方法直接将用户线程修改为守护进程。如果是线程池,需要通过ThreadFactory使线程池中的每个线程都成为守护进程。接下来,我们将分别实现。

  00-1010如果您正在使用线程,您可以通过如下代码所示:.的setDaemon(true)方法将线程类型更改为守护程序

  public static void main(string[]args)抛出中断异常{ thread thread=new thread(new runnable(){ @ override public void run(){ system . out . println(我是子线程));} });//将子线程设置为守护线程. Set daemon(true);system . out . println( child thread==daemon thread: thread . isdaemon());System.out.println(主线程==守护线程: thread.currentthread()。is demon());}以上程序的执行结果

  为:

  

 

  

 

  

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统一设置的,这里就不一一列举了。

  

 

  

3.守护线程 VS 用户线程

通过前面的学习我们可以创建两种不同的线程类型了,那二者有什么差异呢?接下来我们使用一个小示例来看一下。

 

  下面我们创建一个线程,分别将这个线程设置为用户线程和守护线程,在每个线程中执行一个for循环,总共执行 10 次信息打印,每次打印之后休眠 100 毫秒,来观察程序的运行结果。

  

 

  

3.1 用户线程

新建的线程默认就是用户线程,因此我们无需对线程进行任何特殊的处理,执行for循环即可(总共执行 10 次信息打印,每次打印之后休眠 100 毫秒),实现代码如下:

 

  

/** * 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(); }}

以上程序执行结果如下:

 

  

 

  从上述结果可以看出,当程序执行完 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 次之后再进行关闭,而是当主线程结束之后,守护线程只执行了一次循环就结束运行了,由此可以看出守护线程和用户线程的不同。

  

 

  

3.3 小结

守护线程是为用户线程服务的,当一个程序中的所有用户线程都执行完成之后程序就会结束运行,程序结束运行时不会管守护线程是否正在运行,由此我们可以看出守护线程在 Java 体系中权重是比较低的。

 

  

 

  

4.守护线程注意事项

守护线程的使用需要注意以下三个问题:

 

  守护线程的设置setDaemon(true)必须要放在线程的start()之前,否则程序会报错。在守护线程中创建的所有子线程都是守护线程。使用jojn()方法会等待一个线程执行完,无论此线程是用户线程还是守护线程。接下来我们分别演示一下,以上的注意事项。

  

 

  

4.1 setDaemon 执行顺序

当我们将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()之后,不但程序的执行会报错,而且设置的守护线程也不会生效。

  

 

  

4.2 守护线程的子线程

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);}

以上程序执行结果如下:

 

  

 

  从上述结果可以看出,守护线程中创建的子线程,默认情况下也属于守护线程

  

 

  

4.3 join 与守护线程

通过 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()方法时,程序依然会等待守护线程执行完成之后再结束进程。

  

 

  

5.守护线程应用场景

守护线程的典型应用场景就是垃圾回收线程,当然还有一些场景也非常适合使用守护线程,比如服务器端的健康检测功能,对于一个服务器来说健康检测功能属于非核心非主流的服务业务,像这种为了主要业务服务的业务功能就非常合适使用守护线程,当程序中的主要业务都执行完成之后,服务业务也会跟随者一起销毁。

 

  

 

  

6.守护线程的执行优先级

首先来说,线程的类型(用户线程或守护线程)并不影响线程执行的优先级,如下代码所示,定义一个用户线程和守护线程,分别执行 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 时,无论是守护线程还是用户线程,它们执行的优先级都是相同的,当将二者的优先级设置不同时,执行的结果也会随之改变(优先级设置的越高,最早被执行的概率也越大)。

  

 

  

7.总结

在 Java 语言中线程分为用户线程和守护线程,守护线程是用来为用户线程服务的,当一个程序中的所有用户线程都结束之后,无论守护线程是否在工作都会跟随用户线程一起结束。守护线程从业务逻辑层面来看权重比较低,但对于线程调度器来说无论是守护线程还是用户线程,在优先级相同的情况下被执行的概率都是相同的。守护线程的经典使用场景是垃圾回收线程,守护线程中创建的线程默认情况下也都是守护线程。

 

  到此这篇关于Java中用户线程与守护线程的使用区别的文章就介绍到这了,更多相关Java线程内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: