【多线程并发编程】八 线程的礼让和守护线程

程序猿学社的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一样。个人觉得,底层原理还是有学习的必要,这样你才能知其然知其所以然,而不是永远停用在使用的阶段,这也是我们大部分的开发,工作几年后,工资一直上不去的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章