JavaEE 初阶篇-多线程属性和方法

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 创建线程对象并命名

        2.0 线程属性

        2.1 线程属性 - ID

        2.2 线程属性 - 名称

        2.3 线程属性 - 后台线程

        2.4 线程属性 - 判断 PCB 是否存活

        2.5 线程属性 - 终止线程

        3.0 补充细节

        3.1 Thread.sleep() 的异常处理方式

        3.2 变量捕获


        1.0 创建线程对象并命名

语法结构:

//方法一:
Thread t = new Thread(String);

//方法二:
Thread t1 = new Thread(Runnable target String name);

举个例子:

public class demo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true){
                System.out.println("正在执行 run");
            }
        },"自定义名字");
        thread.start();
        while (true){
            System.out.println("正在运行主线程");
        }
    }
}

通过 jconsole 引用程序来查看线程名字:可以发现“自定义名字”这个线程的名称。

        2.0 线程属性

        2.1 线程属性 - ID

        属于线程自己的 ID ,与 PCB 中的属性 PID 不一样,也不是一一对应的。但是线程与 PCB 是一一对应的,编号不是同一个体系。

获取 ID 的方法:

long id = thread.getId();

举个例子:

public class demo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("正在运行 run");
        });
        thread.start();

        long id = thread.getId();
        System.out.println(id);
        System.out.println("正在运行主线程");

    }
}

运行结果:

        也可以通过这个例子发现,手动创建线程是比较慢的,main 线程都执行完毕了,自定义的线程有可能都还没创建完毕。

        2.2 线程属性 - 名称

        获取当前线程的名称,默认名称是:Thread - 0, Thread - 1, Thread - 2 ......

获取线程名称:

        String name = thread.getName();

举个例子:

public class demo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("正在运行 run");
        });
        thread.start();
        String name = thread.getName();
        System.out.println(name);
        System.out.println("正在运行主线程");
    }
}

运行结果:

        2.3 线程属性 - 后台线程

        前台线程:也称为用户线程,当所有的前台线程都结束时,程序就会退出。

        后台线程:也称为守护线程,当所有前台结束时,后台线程会自动被终止,即使后台线程还在执行。后台线程通常用于执行一些辅助性任务,如 gc 垃圾回收,日志记录等。

总的来说,后台线程主要用于支持前台线程的工作,而前台线程则是执行具体的业务逻辑。

        默认都是前台线程,通过设置 daemon 属性来将线程设置为后台线程。

设置 daemon 属性:

Thread thread = new Thread();
thread.setDaemon(true); // 将线程设置为后台线程

举个例子:

public class demo6 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true){
                System.out.println("正在运行 run");
            }
        });
        thread.setDaemon(true);//设置为后台线程
        thread.start();

        // main 是前台线程,因为只有一个前台线程,只要 main 结束了,
        // 那么整个线程都结束了。
        Thread.sleep(1000);

    }
}

运行结果:

        即使 run 方法还没有结束,但是 main 已经结束了,所以整个进程都会结束。需要注意的是:由于这里只有一个 main 前台线程,所以 main 结束,就会影响整个进程结束。

判断是否为后台线程:

boolean b = thread.isDaemon();

        如果是后台线程,那么返回 true ;反则 false 。

举个例子:

public class demo6 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true){
                System.out.println("正在运行 run");
            }
        });
        thread.setDaemon(true);//设置为后台线程
        thread.start();

        // main 是前台线程,因为只有一个前台线程,只要 main 结束了,
        // 那么整个线程都结束了。
        Thread.sleep(1000);
        System.out.println(thread.isDaemon());
        
    }
}

运行结果:

        2.4 线程属性 - 判断 PCB 是否存活

        Thread 对象的生命周期与 PCB 的生命周期是不一定完全一样的。

判断 PCB 是否存活:

Thread t = new Thread();
boolean b = t.isAlive();

        如果 pcb 存活,返回的指是 true ;若反则 false 。

举个例子:

public class demo7 {
    public static void main(String[] args) {

        Thread t = new Thread(() -> {
            System.out.println("正在执行 run");
        });

        //此时上面的 Thread 对象已经创建完成了
        //现在来判断 pcb 是否存活
        System.out.println(t.isAlive());
    }
}

运行结果:

        只要当调用 t.start() 方法后,才会创建线程,那么 pcb 在内核中就创建出来了。

代码如下:

public class demo7 {
    public static void main(String[] args) {

        Thread t = new Thread(() -> {
            System.out.println("正在执行 run");
        });
        t.start();
        //此时上面的 Thread 对象已经创建完成了
        //现在来判断 pcb 是否存活
        System.out.println(t.isAlive());
    }
}

运行结果:

        2.5 线程属性 - 终止线程

        在 Java 中,可以通过调用 Thread 类的 interrupt() 方法来终止线程。这会向线程发送一个中断信号,线程可以通过检查 isInterrupted() 方法来响应中断并做出相应的处理,通常是安全地终止线程的执行。

举个例子:

public class demo8 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {

            // 循环条件是对当前的线程判断是否中断了,
            // 设置:如果中断了,循环停止;如果没有中断,循环继续。
            // 注意注意,这里条件有 ! 。
           while ( !Thread.currentThread().isInterrupted()){
               System.out.println("正在运行 run");
                
                //设置 t 线程休息 9 秒
               try {
                   Thread.sleep(9000);
               } catch (InterruptedException e) {

                   e.printStackTrace();
               }
           }
        });
        
        //创建线程
        t.start();

        //设置 main 线程休息 3 秒,
        //需要注意的是,如果这里不设置休息时间,
        //会导致上面的循环还没进去就被中断了。
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //中断 t 线程
        t.interrupt();
    }
}

运行结果:

        注意结果,即使将 t 线程中断了,但是循环还在继续执行。这是为什么了?

        先来描述整个过程:创建完 t 线程后,在 main 线程等待的时候,t 开始执行 run 方法中的内容,开始的时候,t 线程是没有中断的,可以顺利进入循环。直到 main 线程等待结束之后,将 t 线程中断了,那么即使 t 线程是否处在 sleep() 等待,都会被立即唤醒,不在等待。因此 t.interrupt(); 这段代码可以理解为做了两个动作,第一个动作将 Thread.currentThread().isInterrupted() 的布尔值改变为 true ;第二个动作立即唤醒 sleep() ,不在等待。(如果代码中没有 sleep() 方法对话,该动作就不出现,只有第一个动作)。

        接着,sleep() 被唤醒的同时,1)会自动清除 Thread.currentThread().isInterrupted() 的布尔值改变为 false ,从而导致了代码中的循环继续运行。这就是原因的关键,解释了即使将 t 线程中断了,但是循环还在执行的理由。之所以要改回来,就是把控制权转交给程序员自己。2)sleep() 被唤醒同时会执行 catch() 方法中的代码。

        所以程序员就可以在 catch() 方法中设置自己的思路,假如要中断 t 线程的话,只需要在 catch() 中直接写 break; 即可,就会中断循环了。t 线程也就是结束了。

代码如下:

public class demo8 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
           while ( !Thread.currentThread().isInterrupted()){
               System.out.println("正在运行 run");

               try {
                   Thread.sleep(9000);
               } catch (InterruptedException e) {

                   break;
               }
           }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        t.interrupt();
    }
}

运行结果:

        3.0 补充细节

        3.1 Thread.sleep() 的异常处理方式

        在 main 方法中处理 sleep 有两种选择:1)throws  2)try catch

public class demo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(1000);

    }
}
public class demo12 {
    public static void main(String[] args) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
}

        在线程的 run 中就只有一个选择了:try catch

public class demo10 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("正在执行 run ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        
    }
}

        这是因为 throw 也是方法签名的一部分,在 run 方法重写的时候,就要求方法的签名得是一样的。

        method sign ature 包含:1)方法名字 2)方法的参数列表 3)声明抛出的异常

        3.2 变量捕获

         在 Java 中,变量捕获通常指的是在 Lambda 表达式或匿名内部类中引用外部作用域中的局部变量。当 Lambda 表达式或匿名内部类引用外部作用域的局部变量时,这些变量会被隐式地捕获并保存下来,使得在 Lambda 表达式或匿名内部类中可以访问和修改这些变量的值。

        Lambda 表达式和匿名内部类可以捕获外部作用域中的 final 或 effectively final 局部变量(即不可修改的变量)。

        简单来说,在 Lambda 表达式或者在匿名内部类中要引用外部作用域的局部变量的话,要求该局部变量是常量或者从头到尾都没有修改的变量。

        如果在 Lambda 表达式或匿名内部类中尝试修改非 final 或 effectively final 的局部变量,编译器会报错。这种错误通常称为:

"Local variable is accessed from within inner class, needs to be declared final"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/481890.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis实战篇-1

实战篇Redis 开篇导读 短信登录 这一块我们会使用redis共享session来实现 商户查询缓存 通过本章节,我们会理解缓存击穿,缓存穿透,缓存雪崩等问题,让小伙伴的对于这些概念的理解不仅仅是停留在概念上,更是能在代码…

数据格式化方法

首先你需要一个可以展示代码的组件; 我使用的是tech-ui(内部组件库); 你如果没有类似的组件,可以参考以下链接替代: react-monaco-editor -- 代码编辑器(适用Umi)_umi monaco editor-CSDN博客 Codemirror -- 代码编辑器(react…

Flutter Widget:StatefulWidgetStatelessWidgetState

Widget 概念 Widget 将是构建Flutter应用的基石,在Flutter开发中几乎所有的对象都是一个 Widget 。 在Flutter中的widget 不仅表示UI元素,也表示一些功能性的组件,如:手势 、主题Theme 等。而原生开发中的控件通常只是指UI元素。…

RK3568驱动指南|第十三篇 输入子系统-第145 章 输入子系统上报数据格式分析

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…

CodeSys创建自定义的html5控件

文章目录 背景创建html5control.xml文件控件界面以及逻辑的实现使用的资源安装自定义的html5控件库 背景 查看官方的资料:https://content.helpme-codesys.com/en/CODESYS%20Visualization/_visu_html5_dev.html 官方的例子:https://forge.codesys.com/…

#Linux(VMwareTOOL安装)

(一)发行版:Ubuntu16.04.7 (二)记录: (1) (2)打开虚拟机然后安装,出现灰色可能是已经安装过但是自己没有找到 (3)删除VM…

React【Day1】

B站视频链接 一、React介绍 React由Meta公司开发,是一个用于 构建Web和原生交互界面的库 React的优势 相较于传统基于DOM开发的优势 组件化的开发方式不错的性能 相较于其它前端框架的优势 丰富的生态跨平台支持 React的市场情况 全球最流行,大…

烟火AI识别检测算法在新能源汽车充电桩站点的应用方案

新能源汽车作为现代科技与环保理念的完美结合,其普及和应用本应带给人们更加便捷和绿色的出行体验。然而,近年来新能源汽车充电火灾事故的频发,无疑给这一领域投下了巨大的阴影。这不禁让人深思,为何这一先进的交通工具在充电过程…

OpenCV+OpenCV-Contrib源码编译

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、OpenCV是什么?二、OpenCV 源码编译1.前期准备1.1 源码下载1.2 cmake安装1.3 vscode 安装1.4 git 安装1.5 mingw安装 2.源码编译2.1 打开cmake2.…

【科研基础】VAE: Auto-encoding Variational Bayes

[1]Kingma, Diederik P., and Max Welling. “Auto-encoding variational bayes.” arXiv preprint arXiv:1312.6114 (2013). 文章目录 1-什么是VAE1.1-目标1.2-Intractability:1.3-Approximation use NN:1.4-最大化 L ( θ , ϕ ; x ) L(\theta,\phi;x) L(θ,ϕ;x):1.5-优化 …

数据结构——二叉树-堆(堆的实现,堆排序,TopK问题)

目录 前言 1.树的概念及结构 1.1 树的概念 1.2 树的相关概念 1.3 树的表示 2. 二叉树的概念及结构 2.1概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储结构 3. 堆 3.1 堆的概念及结构 3.2 堆的实现 3.1.2 数据结构的设计和文件准备 3.1.2堆的初始化和销…

小字辈(左子右兄加强版)

文章目录 题目描述思路AC代码总结 题目描述 输入样例1 5 1 2 0 2 4 3 3 0 0 4 0 5 5 0 0 输出样例1 3 4 5输出样例2 5 2 5 3 1 2 0 3 0 0 4 0 0 5 0 4 输出样例2 3 4 5思路 dfs 二叉树 存储结构 1.用结构体数组存储每个节点的父节点、左右节点 2.用vector存储答案 具体做法 1.…

[论文笔记] Dual-Channel Span for Aspect Sentiment Triplet Extraction

一种利用句法依赖和词性相关性信息来过滤噪声(无关跨度)的基于span方法。 会议EMNLP 2023作者Pan Li, Ping Li, Kai Zhang团队Southwest Petroleum University论文地址https://aclanthology.org/2023.emnlp-main.17/代码地址https://github.com/bert-ply…

升级!Sora漫步街头的女人可以跳舞啦!科目三蹦迪多种舞姿停不下来,可精准控制动作

Sora为我们展开了一个充满惊喜的新篇章,同时,Viggle这一模型也吸引了公众的目光,并在推特上迅速走红! 想象一个场景,你仅需用几句话就能让画面活灵活现,无论是让角色跳舞、做后空翻,这些曾经只能…

LeetCode刷题【树状数组、并查集、二叉树】

目录 树状数组307. 区域和检索 - 数组可修改406. 根据身高重建队列673. 最长递增子序列的个数1409. 查询带键的排列 并查集128. 最长连续序列130. 被围绕的区域 二叉树94. 二叉树的中序遍历104. 二叉树的最大深度101. 对称二叉树543. 二叉树的直径108. 将有序数组转换为二叉搜索…

算法 之 排序算法

🎉欢迎大家观看AUGENSTERN_dc的文章(o゜▽゜)o☆✨✨ 🎉感谢各位读者在百忙之中抽出时间来垂阅我的文章,我会尽我所能向的大家分享我的知识和经验📖 🎉希望我们在一篇篇的文章中能够共同进步!!&…

CSS(一)

一、CSS 简介 1.1 HTML 的局限性 说起 HTML&#xff0c;这其实是个非常单纯的家伙&#xff0c;他只关注内容的语义。比如 <h1> 表明这是一个大标题&#xff0c;<p> 表明这是一个段落&#xff0c;<img> 表明这儿有一个图片&#xff0c;<a> 表示此处有链…

PCB产业渐出谷底,超颖电子能否找到发展确定性?

经历了三年多低迷期&#xff0c;消费电子在2024年终于以企稳回升的姿态逐步回暖。IDC预期&#xff0c;2024年&#xff0c;智能手机、PC、服务器等关键领域的出货量或迎来修复性成长。 这也将带动“电子产品之母”印刷电路板&#xff08;Printed Circuit Board&#xff0c;PCB&…

Python之装饰器-无参装饰器

Python之装饰器-无参装饰器 装饰器介绍 1. 为何要用装饰器 Python 中的装饰器是一种语法糖&#xff0c;可以在运行时&#xff0c;动态的给函数或类添加功能。装饰器本质上是一个函数&#xff0c;使用 函数名就是可实现绑定给函数的第二个功能 。将一些通用的、特定函数的功…

InstructGPT的流程介绍

1. Step1&#xff1a;SFT&#xff0c;Supervised Fine-Tuning&#xff0c;有监督微调。顾名思义&#xff0c;它是在有监督&#xff08;有标注&#xff09;数据上微调训练得到的。这里的监督数据其实就是输入Prompt&#xff0c;输出相应的回复&#xff0c;只不过这里的回复是人工…