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"

总结:

  • 守护线程通常用于执行后台任务或辅助功能(如垃圾回收器),它不应该是程序的核心逻辑。
  • 用户线程(前台线程)是程序的核心工作线程,确保程序在完成任务后才退出。
相关推荐
小魏冬琅7 分钟前
探索面向对象的高级特性与设计模式(2/5)
java·开发语言
lihao lihao10 分钟前
C++stack和queue的模拟实现
开发语言·c++
TT哇21 分钟前
【Java】数组的定义与使用
java·开发语言·笔记
天天进步201526 分钟前
Lodash:现代 JavaScript 开发的瑞士军刀
开发语言·javascript·ecmascript
假装我不帅35 分钟前
js实现类似与jquery的find方法
开发语言·javascript·jquery
look_outs39 分钟前
JavaSE笔记2】面向对象
java·开发语言
萧鼎40 分钟前
【Python】高效数据处理:使用Dask处理大规模数据
开发语言·python
武子康43 分钟前
大数据-191 Elasticsearch - ES 集群模式 配置启动 规划调优
java·大数据·elk·elasticsearch·搜索引擎·全文检索
A_aspectJ1 小时前
‌Spring MVC的主要组件有哪些?
java·spring·mvc
塔塔开!.1 小时前
Maven的依赖
java·maven