网上的资料中,守护线程的功能一般都是“只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束是,守护线程随着JVM一同结束工作,Daemon作用是为其他线程提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),他就是一个很称职的守护者。”
可是,我发现真实情况却不是描述的这么回事,因为我对java也不懂,所以在此记录一下守护线程中的一些问题。

我的思路是:
在main线程中建立两个线程,一个线程A只打印一行信息就退出,它被设置成守护线程,另一个线程B通过sleep和循环来进行时间控制,让它多运行一会,他被设置成非守护线程。如果按照上面的说明,我认为线程A怎么说也要和线程B的消亡时间是一样的。实际情况却不是这样的。
下面是代码:

文件 ThreadDaemon.java

package javaStudy.threadStudy;

import java.util.Date;

public class ThreadDaemon {
public static void main(String[] args) {
// Thread.currentThread().setDaemon(true);
// Thread.currentThread().start();
// 系统的main函数使用一个主线程,主线程不是守护线程,也不能被设置成守护线程
System.out.println(Thread.currentThread().getName() + "\tprocess begin\t" + (new Date()) + "\t"
+ Thread.currentThread().isDaemon() + "\tthread amount\t"
+ Thread.currentThread().getThreadGroup().activeCount());
showThreadName();
// 新建一个线程,并将其设置成守护线程,他的操作仅仅是打印一行信息。
Thread t = new Thread(ThreadDaemon::daemonPrint);
t.setDaemon(true);
t.start();
System.out.println(Thread.currentThread().getName() + "\tafter create thread A\t" + (new Date()) + "\t"
+ Thread.currentThread().isDaemon() + "\tthread amount\t"
+ Thread.currentThread().getThreadGroup().activeCount());
showThreadName(); // 再建立一个线程,将其设置成用户线程,即非守护线程。让他多执行一会。
try {
Thread.sleep(1000 * 3);
Thread thread2 = new Thread(ThreadDaemon::print);
thread2.setDaemon(false);
thread2.start();
System.out.println(Thread.currentThread().getName() + "\tafter create thread B\t" + (new Date()) + "\t"
+ Thread.currentThread().isDaemon() + "\tthread amount\t"
+ Thread.currentThread().getThreadGroup().activeCount());
showThreadName();
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println(Thread.currentThread().getName() + "\tExit:" + "\t" + (new Date()) + "\t"
+ Thread.currentThread().isDaemon() + "\tthread amount "
+ Thread.currentThread().getThreadGroup().activeCount());
showThreadName();
// System.exit(0) 是退出jvm。如果有此代码,则子线程也会直接随着主线程而退出。如果没有此代码,jvm会在子线程结束的时候而退出。
// System.exit(0);
} // 用户线程的调用
public static void print() {
int counter = 1;
while (counter < 5) {
try {
Thread.sleep(3 * 1000); // sleep for 10 seconds
System.out.println(Thread.currentThread().getName() + "\tbefore Counter:" + counter++ + "\t"
+ (new Date()) + "\t" + Thread.currentThread().isDaemon() + "\tthread amount "
+ Thread.currentThread().getThreadGroup().activeCount());
Thread.sleep(3 * 1000); // sleep for 10 seconds
System.out.println(Thread.currentThread().getName() + "\tafter Counter:" + counter++ + "\t"
+ (new Date()) + "\t" + Thread.currentThread().isDaemon() + "\tthread amount "
+ Thread.currentThread().getThreadGroup().activeCount());
showThreadName();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} // 守护线程的调用
public static void daemonPrint() {
try {
Thread.sleep(6 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println(
Thread.currentThread().getName() + "\t" + (new Date()) + "\t" + Thread.currentThread().isDaemon()
+ "\tthread amount " + Thread.currentThread().getThreadGroup().activeCount());
showThreadName();
} // 显示线程名称
public static void showThreadName() {
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
int noThreads = currentGroup.activeCount();
Thread[] lstThreads = new Thread[noThreads];
currentGroup.enumerate(lstThreads);
for (int i = 0; i < noThreads; i++) {
System.out.println("==============="+lstThreads[i].getName() + "\t" + lstThreads[i].isDaemon());
}
}
}

以上代码,我根据程序休眠的时间,让主线程先退出,然后发现守护线程却在第二个退出的。因为他不是死循环,所以提前退出了?这么说来,如果一个线程要想是守护线程的话,他必须是死循环?也就是说,从程序表面看,守护线程一定要比用户线程存活的久一点?这么说来,将一个理论上活的更久的线程,设置成守护线程,仅仅是让它自动和用户线程一起消亡罢了。实际上,通过延长上面代码的daemonPrint()的sleep的时间,也可以验证守护线程会和用户线程一起消亡。

下面是程序的日志:

main process begin Tue Oct 16 17:17:29 CST 2018 false thread amount 1
===============main false
main after create thread A Tue Oct 16 17:17:30 CST 2018 false thread amount 2
===============main false
===============Thread-0 true
main after create thread B Tue Oct 16 17:17:33 CST 2018 false thread amount 3
===============main false
===============Thread-0 true
===============Thread-1 false
main Exit: Tue Oct 16 17:17:33 CST 2018 false thread amount 3
===============main false
===============Thread-0 true
===============Thread-1 false
Thread-0 Tue Oct 16 17:17:36 CST 2018 true thread amount 3
===============Thread-0 true // 这一行日志,说明他是守护线程,但是下面却没有了他的名字。因为他不是死循环,所以提前退出了?
===============Thread-1 false
===============DestroyJavaVM false
Thread-1 before Counter:1 Tue Oct 16 17:17:36 CST 2018 false thread amount 2
Thread-1 after Counter:2 Tue Oct 16 17:17:39 CST 2018 false thread amount 2
===============Thread-1 false
===============DestroyJavaVM false
Thread-1 before Counter:3 Tue Oct 16 17:17:42 CST 2018 false thread amount 2
Thread-1 after Counter:4 Tue Oct 16 17:17:45 CST 2018 false thread amount 2
===============Thread-1 false
===============DestroyJavaVM false

结论:代码的逻辑让守护线程提前于用户线程消亡的情况下,守护线程并不会主动延长生命和用户线程一起消亡。但是,代码的逻辑让守护线程延迟于用户线程消亡的情况下,守护线程会提前和用户线程一起消亡。这样也可以理解,毕竟CPU资源那么金贵,既然守护线程提前与用户线程消亡,那他没有必要赖着占用CPU的资源,对吧?

java中守护线程的一些概念和用法的更多相关文章

  1. Java中守护线程的总结 thread.setDaemon(true)

    https://www.cnblogs.com/ziq711/p/8228255.html 在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用个比较 ...

  2. Java中守护线程的总结

    在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆: 只要当前JVM实例中尚存 ...

  3. 在 java 中守护线程和本地线程区别?

    java 中的线程分为两种:守护线程(Daemon)和用户线程(User). 任何线程都可以设置为守护线程和用户线程,通过方法 Thread.setDaemon(bool on):true 则把该线程 ...

  4. Java多线程编程(1)--Java中的线程

    一.程序.进程和线程   程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...

  5. 并发王者课 - 青铜 2:峡谷笔记 - 简单认识Java中的线程

    在前面的<兵分三路:如何创建多线程>文章中,我们已经通过Thread和Runnable直观地了解如何在Java中创建一个线程,相信你已经有了一定的体感.在本篇文章中,我们将基于前面的示例代 ...

  6. 【Java中的线程】java.lang.Thread 类分析

    进程和线程 联想一下现实生活中的例子--烧开水,烧开水时是不是不需要在旁边守着,交给热水机完成,烧开水这段时间可以去干一点其他的事情,例如将衣服丢到洗衣机中洗衣服.这样开水烧完,衣服洗的也差不多了.这 ...

  7. 浅谈利用同步机制解决Java中的线程安全问题

    我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等 ...

  8. java笔记--守护线程的应用

    守护线程的应用 Java中的线程可以分为两类,即用户线程和守护线程.用户线程是为了完成任务,而守护线程是为其他线程服务 --如果朋友您想转载本文章请注明转载地址"http://www.cnb ...

  9. Java中的线程同步

    Java 中的线程同步问题: 1. 线程同步: 对于访问同一份资源的多个线程之间, 来进行协调的这个东西. 2. 同步方法: 当某个对象调用了同步方法时, 该对象上的其它同步方法必须等待该同步方法执行 ...

随机推荐

  1. caffe2+cuda+Ubuntu16.04(u盘安装)

    安装caffe2 预先准备.安装gflags及autoconf及GLOG https://github.com/caffe2/caffe2/issues/1810 一.下载源代码通过网盘 https: ...

  2. 解题报告:hdu1248寒冰王座 - 完全背包模板

    2017-09-03 16:16:38 writer:pprp 完全背包问题:从左向右进行扫描,用一维阵列进行分析 代码如下: /* @theme:hdu1248 寒冰王座 @writer:pprp ...

  3. Class.forName()与newInstance()

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sq ...

  4. Android -- ContentProvider, 读取和保存系统 联系人

    1. 示例代码 需要的读写联系人的权限 <uses-permission android:name="android.permission.WRITE_CONTACTS"/& ...

  5. 简单UML

    http://www.cnblogs.com/pluviophile/p/7542017.html,看了这篇博文感觉这个例子有用遂搬运过来方便查阅 上面的类图就体现了所需要了解的类的6个基本关系 该类 ...

  6. UTF-8文件的Unicode签名BOM(Byte Order Mark)问题记录(EF BB BF)

    背景 楼主测试的批量发送信息功能上线之后,后台发现存在少量的ERROR日志,日志内容为手机号码格式不正确. 此前测试过程中没有出现过此类问题,从运营人员拿到的发送列表的TXT,号码是符合规则的,且格式 ...

  7. vue-router的一个小实例

    非2.0的 vue2.0还有vue-router2.0的改变还是挺大的 vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用.vue的单页面应用是基于 ...

  8. 使用idea引入注解@SpringBootApplication报错Cannot resolve symbol 'SpringBootApplication'

    我在使用idea时,在类上使用注解@SpringBootApplication,但是一直报错. Cannot resolve symbol 'SpringBootApplication' 网络上有很多 ...

  9. 重新学习MySQL数据库3:Mysql存储引擎与数据存储原理

    重新学习Mysql数据库3:Mysql存储引擎与数据存储原理 数据库的定义 很多开发者在最开始时其实都对数据库有一个比较模糊的认识,觉得数据库就是一堆数据的集合,但是实际却比这复杂的多,数据库领域中有 ...

  10. Spring源码解析-IOC容器的实现

    1.IOC容器是什么? IOC(Inversion of Control)控制反转:本来是由应用程序管理的对象之间的依赖关系,现在交给了容器管理,这就叫控制反转,即交给了IOC容器,Spring的IO ...