1 JVM线程分类
1.1 分类
- 用户线程
- 守护线程 Daemon Thread
1.2 守护线程tips
- 两者唯一的区别只是jvm判断何时离开的问题(生命周期问题)
- 当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出
- 守护线程是服务用户线程的,在start方法前调用setDaemon(true)把用户线程变成守护线程
- 典型的守护线程便是java垃圾回收
- jvm如果都是守护线程,jvm会退出(可以理解main线程执行结束 不再有用户线程)
- 一个普通的应用程序java.exe代表操作系统启动了一个jvm进程,而一个jvm进程中至少有三个线程: main gc 线程,后两者都是守护线程
2 守护线程生命周期
- 只要JVM中尚存任何一个用户线程没有结束,守护线程就不会消亡且会工作
- 只有当最后一个用户线程消亡,守护线程会跟着消亡
3 作用
- 为其他线程的运行提供服务 如GC
4 实验
4.1 实验一:父线程设置为守护线程,那么创建的子线程也是守护线程
-
子线程
@Slf4j public class ChildThread implements Runnable{ @Override public void run() { while (true){ log.info("I am a child thread.."); try{ TimeUnit.MILLISECONDS.sleep(5000); }catch (Exception e){ e.printStackTrace(); } } } }
-
父线程改动
@Slf4j
public class DaemonMain {
public static void main(String[] args) {
Thread fatherThread = new Thread(){
@Override
public void run() {
Thread childThread = new Thread(new ChildThread());
childThread.setName("child Thread");
//childThread.setDaemon(true);
childThread.start();
log.info("I am a main thread..");
}
};
fatherThread.setDaemon(true);
fatherThread.setName("Father Thread");
fatherThread.start();
log.info("over..");
}
}
-
输出
22:27:27.801 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 22:27:27.804 [main] INFO com.uestc.chapter04.DaemonMain - over.. 22:27:27.801 [Father Thread] INFO com.uestc.chapter04.DaemonMain - I am a main thread..
-
详解
-
父线程设置为守护线程,那么创建的子线程也是守护线程(尽管无线循环)
-
所以一定要让主线程跑业务,子线程设置为守护线程(主线程不能设置守护线程)
-
4.2 实验二:被守护线程结束,守护线程也将结束(子线程为守护线程,父线程用户线程)
- 子线程定义
@Slf4j
public class ChildThread implements Runnable{
@Override
public void run() {
while (true){
log.info("I am a child thread..");
try{
TimeUnit.MILLISECONDS.sleep(5000);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
-
主线程定义
//mainThread 是通过new thread形式创建 //childthread守护线程是通过接口形式创建 @Slf4j public class DaemonMain { public static void main(String[] args) { Thread fatherThread = new Thread(){ @Override public void run() { Thread childThread = new Thread(new ChildThread()); childThread.setName("child Thread"); childThread.setDaemon(true); childThread.start(); log.info("I am a main thread.."); } }; //mainThread.setDaemon(true); fatherThread.setName("Father Thread"); fatherThread.start(); log.info("over.."); } } /* 注意:该案例中是设立子线程为守护线程。如果该案例设置父线程为守护线程,子线程同样会结束,父为守护,子也为守护线程,即案列二 */
-
输出
22:19:30.189 [main] INFO com.uestc.chapter04.DaemonMain - over.. 22:19:30.192 [Father Thread] INFO com.uestc.chapter04.DaemonMain - I am a main thread.. 22:19:30.191 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread..
-
详解
-
这里的main线程不是指代public static void main的这个线程,只是实验变量取名巧合了
-
尽管你ChildThread守护线程(子线程)是个死循环,但是当它守护的Father Thread线程结束时(I am a main thread…执行完毕),被守护的线程(child Thread)也跟着结束。
-
4.3 实验三: 整个jvm中只要有用户线程,则守护线程不会结束
-
子线程定义:
@Slf4j public class ChildThread implements Runnable{ @Override public void run() { while (true){ log.info("I am a child thread.."); try{ TimeUnit.MILLISECONDS.sleep(5000); }catch (Exception e){ e.printStackTrace(); } } } }
-
主线程定义:
Thread fatherThread = new Thread(new Runnable(){ @Override public void run(){ Thread childThread = new Thread(new ChildThread()); childThread.setDaemon(true); childThread.setName("child Thread"); childThread.start(); log.info("I am a Father thread.."); } }); fatherThread.setName("Father Thread"); fatherThread.start(); Thread otherThread = new Thread(new Runnable() { @Override public void run() { while(true){ log.info("I am a other thread"); try{ TimeUnit.MILLISECONDS.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } }){}; otherThread.setName("otherThread Thread"); otherThread.start();
-
输出
22:53:39.503 [Father Thread] INFO com.uestc.chapter04.DaemonMain - I am a Father thread..//输出一次 father线程执行结束 22:53:39.504 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 22:53:39.504 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:40.513 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:41.516 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:42.516 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:43.520 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:44.510 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 22:53:44.523 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:45.525 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:46.529 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:47.535 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:48.537 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:49.515 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 22:53:49.540 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:50.541 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:51.543 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:52.548 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:53.549 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:54.517 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 22:53:54.549 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:55.552 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:56.553 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:57.558 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:58.562 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:53:59.522 [child Thread] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 22:53:59.565 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:54:00.570 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:54:01.575 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:54:02.579 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread 22:54:03.583 [otherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a other thread . . .
-
解析
- 尽管Father Thread线程结束,但是守护线程childThread监控到jvm中的用户线程还有otherThread(在while循环),因此程序会一直打印不会退出。所以说守护线程守护的范围不仅仅是父子,而是整个jvm是否有用户线程
4.4 实验四 指定线程组 守护线程仍然守护
-
子线程定义: 如上
-
主线程
Thread mainThread = new Thread(new Runnable(){ @Override public void run(){ Thread childThread = new Thread(new ChildThread()); childThread.setDaemon(true); childThread.start(); System.out.println("I'm main thread..."); } }); mainThread.start(); ThreadGroup selfThreadGroup = new ThreadGroup("selfThreadGroup"); //创建线程的时候指定线程所属的线程组-selfThreadGroup Thread otherThread = new Thread(selfThreadGroup,new Runnable() { @Override public void run() { while(true){ System.out.println("I am a other thread."); try{ TimeUnit.MILLISECONDS.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } }){}; otherThread.start();
-
输出
I am a other thread. I'm main thread... I am a child thread. I am a other thread. I am a child thread. I am a other thread. I am a child thread. I am a other thread. I am a child thread.
详解
-
尽管自定义创建了线程组,但是selfThreadGroup隶属于main的线程组的子(不允许创建孤立线程组)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXqMThim-1619536169062)(/Users/yuminghua/Library/Application Support/typora-user-images/image-20200507211111053.png)]
-
尽管otherThread分配到了ThreadGroup中,但是也属于用户线程,所以也不会结束
-
4.5 实验五 守护线程采用线程池的方式开启(守护线程将变成用户线程)
-
子线程: 如上
-
主线程:
Thread fatherThread = new Thread(new Runnable(){ @Override public void run() { ExecutorService exec = Executors.newCachedThreadPool(); Thread childThread = new Thread(new ChildThread()); childThread.setDaemon(true); childThread.setName("childThread Thread"); exec.execute(childThread); exec.shutdown(); log.info("I am a Father thread.."); } }); fatherThread.setName("fatherThread Thread"); fatherThread.start(); }
-
输出
23:07:18.642 [fatherThread Thread] INFO com.uestc.chapter04.DaemonMain - I am a Father thread.. 23:07:18.642 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:23.649 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:28.651 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:33.655 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:38.659 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:43.661 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:48.666 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:53.667 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:07:58.667 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:08:03.671 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:08:08.675 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. 23:08:13.679 [pool-1-thread-1] INFO com.uestc.chapter04.ChildThread - I am a child thread.. . . .
-
详解
-
尽管被设置成了守护线程,但是以线程池的方式被开启,该守护线程会变成用户线程(优先级变成Thread.NORM_PRIORITY)
-
线程池开启的线程都会把守护线程设置失效,且优先级调整成Normal
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwIehNgl-1619536169064)(/Users/yuminghua/Library/Application Support/typora-user-images/image-20200507214224866.png)]
-