程序猿学社的GitHub,欢迎Star
https://github.com/ITfqyd/cxyxs
本文已记录到github,形成对应专题。
前言
上一篇文章,我们了解线程的优先级,这次,我们一起来学习一下线程的礼让和守护。听起来是不是一脸懵逼,别急,我们来一一了解。
1.线程的礼让
什么是线程的礼让
线程的礼让,就是让出自己抢到的执行权,也就是我们所说的时间片,让出执行权,并不意味着,该线程不参与下轮的争抢勒。
yield方法
打开Thread类,通过alt+7(idea版本),我们可以快速找到该方法。
public static native void yield();
- 我们可以看到有一个关键字native,但是,我们找不到具体的方法,说明他是通过C或者C++实现的,使用native关键字说明这个方法是原生函数。
- 如果用使用过java调用dll文件的社友,就会觉得这个很熟悉,熟悉的味道。
为什么不通过java实现?
- 我们查看jdk源码,可以发现有不少方法被修饰为native,Java 1.1开始就引入了JNI,如果我们想与操作系统进行交互,就需要通过JNI与操作系统进行交互。
yield实战
package com.cxyxs.thread.eight;
/**
* Description:转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/26 19:05
* Modified By:
*/
public class YieldThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",早上打卡上班");
Thread.yield();
System.out.println(Thread.currentThread().getName()+",晚上打卡下班");
}
public static void main(String[] args) {
YieldThread yieldThread = new YieldThread();
Thread t = new Thread(yieldThread,"程序猿学社");
Thread t1 = new Thread(yieldThread,"隔壁老王");
t.start();
t1.start();
}
}
交替运行
先运行玩完一个线程,再运行另外一个线程。
- 通过多次测试,我们可以得出一个结论。调用yield方法会使线程让出当前的执行权,但是,并不代表,他不参与下轮的时间片的争抢。
- 调用该方法会使线程从运行状态切换到就绪状态。
- 下一次再拿到时间片后,会继续从调用yield方法后的下一句代码开始运行。
2.守护线程
守护线程的概念
java线程可以划分为两种:
- 用户线程(我们自定义的线程)
- 守护线程(就是为他人服务的,当java进程中没有用户线程时,他就会自动销毁),我们常见的有垃圾回收线程。
案例:
守护线程可以理解为玄幻小说里面的宠物,跟主人签订了主从协议,主人身死,自己也会死掉。
守护线程场景
- 我们的垃圾回收线程就是一个守护线程,为什么要设计成守护线程,他就是为了保证,所有的用户线程都退出后,直接不产生新的垃圾后,作为我们java的雷锋同志垃圾回收线程,才会默默地消失。
- 通过查看Timer定时器的源码,我们可以发现,他竟然可以传参数设置是否为守护线程。
代码实战
package com.cxyxs.thread.eight;
/**
* Description:守护线程
* 转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/27 0:31
* Modified By:
*/
public class WatchThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
try {
System.out.println("程序猿学社:第"+i+"次打卡");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
WatchThread watchThread = new WatchThread();
Thread thread = new Thread(watchThread);
thread.setDaemon(true); //设置线程为守护线程
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main线程已结束!");
}
}
- 不设置setDaemon,通过Thread源码,可以发现默认值为false,也就是说,我们自定义的线程,如果再不手动设置为true的前提下,自定义的线程都是用户线程。
- 通过测试,我们可以发现main线程已经打印结束的情况下,从线程还在运行。一直在不停的打印。
- main线程是用户线程,不是守护线程,这里验证完毕,有不少社友认为main线程是守护线程。
- setDaemon方法为true,表示设置为守护线程。
- 在没有用户线程的情况下,进程会自动退出。其他的守护线程也会自动销毁。
验证线程是否为守护线程
package com.cxyxs.thread.eight;
/**
* Description:转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/27 1:11
* Modified By:
*/
public class Demo1 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"线程");
System.out.println(Thread.currentThread().isDaemon());
}
}
- 通过这个案例,我们应该知道main线程不是守护线程了把。
总结:实际上,在我们日常的开发过程中,几乎都不会用到线程的礼让和守护线程。但是,我们为什么需要去了解他。这种问题,就类似于我们学习springboot是否还需要学习springmvc一样。个人觉得,底层原理还是有学习的必要,这样你才能知其然知其所以然,而不是永远停用在使用的阶段,这也是我们大部分的开发,工作几年后,工资一直上不去的原因。