JavaEE 多线程第三节 (lambda方法实现多线程/Thread属性和方法/前台线程后台线程)

欢迎阅读前序课程JavaEE 多线程第二节 (多线程的简单实现Thread/Runable)-CSDN博客

1. lambda方法实现多线程

java 复制代码
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while (true){
                System.out.println("helloworld");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();

        while (true){
            System.out.println("Hello Main");
            Thread.sleep(1000);
        }
    }
}

2. Thread属性和方法

1. 属性----->名称

java 复制代码
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while (true){
                System.out.println("helloworld");
                try {
                    Thread.sleep(1000);
                 } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"自定义线程");
        t.start();

        while (true){
            System.out.println("Hello Main");
            Thread.sleep(1000);
        }
    }
}

可以从jconsole查看

2.方法

java 复制代码
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while (true){
                System.out.println("helloworld");
                try {
                    Thread.sleep(1000);
                 } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"自定义线程");
        t.start();

        System.out.println("线程ID"+ t.getId());
        System.out.println("线程名字"+ t.getName());
        System.out.println("线程状态"+ t.getState());
        System.out.println("线程优先级"+t.getPriority());
    }
}

isAlive

运行结果:

  • t.start() 之前,t.isAlive() 返回 false,因为线程还没有启动。
  • 调用 t.start() 之后,线程开始执行任务,此时 t.isAlive() 返回 true
  • 主线程通过 Thread.sleep(5000) 休眠 5 秒,确保给线程 t 足够的时间去完成任务(线程 t 每次休眠 1 秒,总共循环 3 次,因此需要约 3 秒完成)。
  • t 线程的任务执行完后,t.isAlive() 再次返回 false,因为线程已经结束。

关键点:

  1. 线程状态
    • isAlive() 方法用于检查线程是否还在运行。当线程启动并未终止时,返回 true;否则返回 false
  2. 线程执行过程
    • 你创建了一个线程 t,其任务是在循环中打印 "helloworld" 三次,每次打印后休眠 1 秒。通过 t.start() 启动线程,JVM 会为这个线程分配时间片执行任务。
  3. 线程的生命周期
    • 线程的状态会经历几个阶段:
      1. 新建状态(New) :线程 t 刚创建时,还未调用 start()
      2. 就绪状态(Runnable) :调用 start() 之后,线程进入就绪状态,等待 JVM 调度执行。
      3. 运行状态(Running) :线程被调度并开始执行 run() 方法中的代码。
      4. 终止状态(Terminated) :当 run() 方法执行完毕,线程进入终止状态,此时 isAlive() 返回 false

3. 前台线程后台线程

1. 前台线程 vs 后台线程

  • 前台线程(用户线程):

    • 默认情况下,Java中的线程都是前台线程。
    • JVM不会终止,直到所有前台线程都结束。如果有任何前台线程还在运行,JVM会继续执行。
    • 举例:在你的代码中,如果你不调用 t.setDaemon(true),线程 t 就是一个前台线程,意味着即使 main 方法结束,JVM也不会退出,因为 t 线程在不停地输出 "helloworld"
  • 后台线程(守护线程):

    • 后台线程通常是为其他线程提供服务的线程,比如垃圾回收线程。
    • JVM会在所有前台线程都结束后终止,不管后台线程是否还在运行
    • 通过 Thread.setDaemon(true) 将一个线程设为后台线程。
    • 如果你设置了 t.setDaemon(true),意味着 t 是一个后台线程,当 main 线程(前台线程)结束后,JVM会终止,后台线程 t 也会随之停止,不再继续运行。

2. 结合代码讲解

java 复制代码
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while (true){
                System.out.println("helloworld");
                try {
                    Thread.sleep(1000);
                 } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"自定义线程");
        t.setDaemon(true);
        t.start();
        //t变为守护线程不能组织线程结束

    }
}

运行一次就结束了

3. 执行流程

  • Thread t 是一个线程对象,线程的任务是通过 lambda 表达式定义的,循环输出 "helloworld" 并每秒钟休眠一次。
  • t.setDaemon(true) 这行代码将 t 线程设为守护线程 。这意味着,当所有前台线程结束时 ,守护线程 t 也会结束,而不管它是否仍然在运行。
  • t.start() 启动线程 t,线程进入运行状态,开始打印 "helloworld"
  • 重点 :由于 t 是后台线程,当 main 方法执行结束,JVM 会停止所有后台线程并终止运行。因此,t 的运行时间会非常短暂。

4. 前台和后台线程的区别总结

  • 前台线程 (用户线程):
    • 会阻止 JVM 退出。
    • 即使所有后台线程结束,前台线程还在运行,JVM 也不会停止。
  • 后台线程 (守护线程):
    • 当所有前台线程结束时,JVM 会终止,即使后台线程还在运行。
    • 守护线程通常用于执行一些后台服务,比如垃圾回收。

5. 关于这段代码的实际行为

如果你将 t.setDaemon(true) 改为 t.setDaemon(false)(或者直接不调用它,默认是前台线程),t 就变为前台线程。此时,即使 main 线程结束,JVM 也会继续运行,因为 t 线程还在运行,它会一直每秒钟输出 "helloworld"

然而,使用了 t.setDaemon(true) 后,t 成为后台线程。当 main 线程结束时,t 线程会立即终止,不再输出 "helloworld"

总结:

  • 守护线程通常用于执行后台任务或辅助功能(如垃圾回收器),它不应该是程序的核心逻辑。
  • 用户线程(前台线程)是程序的核心工作线程,确保程序在完成任务后才退出。
相关推荐
码农飞飞几秒前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货2 分钟前
Rust 的简介
开发语言·后端·rust
shuangrenlong3 分钟前
slice介绍slice查看器
java·ubuntu
牧竹子3 分钟前
对原jar包解压后修改原class文件后重新打包为jar
java·jar
湫ccc10 分钟前
《Python基础》之基本数据类型
开发语言·python
Matlab精灵11 分钟前
Matlab函数中的隐马尔可夫模型
开发语言·matlab·统计学习
Microsoft Word12 分钟前
c++基础语法
开发语言·c++·算法
数据小爬虫@14 分钟前
如何利用java爬虫获得淘宝商品评论
java·开发语言·爬虫
喜欢猪猪15 分钟前
面试题---深入源码理解MQ长轮询优化机制
java
qq_1728055922 分钟前
RUST学习教程-安装教程
开发语言·学习·rust·安装