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

news2024/11/15 4:47:18

🔥博客主页: 【小扳_-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"

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库管理-第163期 19c重建ADG的两个方法(20240323

数据库管理163期 2024-03-23 数据库管理-第163期 19c重建ADG的两个方法(20240323)1 ORA-081032 新办法1 关闭MRP2 恢复备库3 其他操作4 启动备库5 启动MRP 3 老办法4 预告总结 数据库管理-第163期 19c重建ADG的两个方法(20240323)…

Stompy:一款针对时间戳的Timestomp工具

关于Stompy Stompy是一款功能强大的时间戳管理工具,在该工具的帮助下,广大研究人员能够轻松对指定文件或目录的时间戳进行修改和操作。该工具基于PowerShell开发,并且支持对目标目录中的所有文件执行递归时间戳操作。 功能介绍 1、修改独立…

有什么可以下载网页视频的浏览器插件 浏览器如何下载网页视频 网页视频怎么下载到本地 网页视频下载软件 IDM下载

在视频网站上看电影追剧,已经成为了大众生活中必不可少的一部分。为了保护自家视频的版权,很多平台都禁止用户下载会员视频。其实只要掌握了正确的方法,一样可以将会员视频下载到本地保存。那么有关有什么可以下载网页视频的浏览器&#xff0…

Fast-R-CNN论文笔记

目标检测之Fast R-CNN论文精讲,Fast RCNN_哔哩哔哩_bilibili 一 引言 1.1 R-CNN和SPPNet缺点 😀R-CNN Training is a multi-stage pipeline 多阶段检测器(两阶段和一阶段检测器) 1️⃣首先训练了一个cnn用来提取候选区域的特征…

JMeter并发工具的使用

视频地址:Jmeter安装教程01_Jmeter之安装以及环境变量配置_哔哩哔哩_bilibili 一、JMeter是什么 JMeter是一款免安装包,官网下载好后直接解压缩并配置好环境变量就可以使用。 环境变量配置可参考:https://www.cnblogs.com/liulinghua90/p/…

只有IP地址怎么实现HTTPS访问?

只有IP地址也可以实现HTTPS访问。虽然大部分SSL证书通常是针对域名发放,但也存在专门针对IP地址发放的SSL证书,这类证书允许服务器通过HTTPS协议为其公网IP地址提供安全的Web服务。当服务器配置了基于IP地址的SSL证书后,用户可以通过“https:…

git基础-查看提交历史

查看提交历史 在创建了多个提交之后,或者如果克隆了一个具有现有提交历史的存储库,可能会想要回顾一下发生了什么。最基本和强大的工具就是 git log 命令。 运行下git log查看下输出状态 默认情况下,不带任何参数运行 git log 命令会以逆时…

Java之继承和多态(精简版-更适合复习)

继承 如果子类有,优先访问子类的,子类没有,然后去看父类有没有,父类也没有,那就会报错。 就是要访问父类怎么办?通过super关键字。 在静态方法当中,时不能使用this和super的。 当子类继承了父…

江苏开放大学2024年春《中级会计实务(上) 050284》第1次任务第一单元总论、第二单元存货练习参考答案

答案:更多答案,请关注【电大搜题】微信公众号 答案:更多答案,请关注【电大搜题】微信公众号 答案:更多答案,请关注【电大搜题】微信公众号 电大搜题 多的用不完的题库&#xff…

院子摄像头的监控

院子摄像头的监控和禁止区域入侵检测相比,多了2个功能:1)如果检测到有人入侵,则把截图保存起来,2)如果检测到有人入侵,则向数据库插入一条事件数据。 打开checkingfence.py,添加如下…

2024阿里云学生服务器免费领取申请(2024新版教程)

阿里云学生服务器免费申请,之前是云翼计划学生服务器9元/月,现在是高校计划,学生服务器可以免费申请,先完成学生认证即可免费领取一台云服务器ECS,配置为2核2G、1M带宽、40G系统盘,在云服务器ECS实例过期之…

大学期末考试搜题软件?这4款足够解决问题 #知识分享#笔记#职场发展

当代大学生面临着繁重的学业压力和海量的知识点,如何高效地进行学习和搜题成了他们关注的焦点。幸运的是,随着科技的不断进步,我们有越来越多的日常搜题和学习软件可以帮助我们更好地应对这些挑战。在本文中,我将为大家介绍10款备…

软考复习笔记day3(计算机体系结构和指令系统基础)(精简版)

计算机体系结构分类 处理机数量分类: 单处理(一个处理单元)并行处理系统(两个以上处理机互联).分布式处理系统 Flynn分类:(常考) 以指令流和数据流进行区别 指令流由控制部分进…

day03_mysql_课后练习 - 参考答案

文章目录 day03_mysql_课后练习mysql练习题第1题第2题第3题第4题第5题 day03_mysql_课后练习 mysql练习题 第1题 案例: 1、创建一个数据库:day03_test01_school 2、创建如下表格 表1 Department表的定义 字段名字段描述数据类型主键外键非空唯一D…

算法 之 排序算法

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

总结 | vue3项目初始化(附相应链接)

如何运行 vue 项目:vscode运行vue项目_vscode启动vue项目命令-CSDN博客 vue3项目搭建 目录管理 git管理:vue3项目搭建并git管理_git 新建vue3项目-CSDN博客 目录调整:vue3项目 - 目录调整-CSDN博客 vscode中快速生成vue3模板&#xff1a…

12 Games101 - 笔记 - 几何(网格处理)、阴影图

12 几何(网格处理)、阴影图 曲面细分 曲面细分是指将一个模型的面合理的分成更多小的面,从而提升模型精度,使模型越来越光滑,提高渲染效果。 Loop细分 Loop细分是指Loop提出来的细分规则,只能针对于三角…

中等职业学校大数据课程建设方案

大数据产业是以数据及数据所蕴含的信息价值为核心生产要素,通过数据技术、数据产品、数据服务等形式,使数据与信息价值在各行业经济活动中得到充分释放的赋能型产业。 大数据产业定义一般分为核心业态、关联业态、衍生业态三大业态。 一、专…

【Entity Framework】 EF中DbContext类详解

【Entity Framework】 EF中DbContext类详解 一、概述 DbContext类是实体框架的重要组成部分。它是应用域或实例类与数据库交互的桥梁。 从上图可以看出DbContext是负责与数据交互作为对象的主要类。DbContext负责以下活动: EntitySet:DbContext包含…

golang sync.Map之如何设计一个并发安全的读写分离结构?

在 golang中,想要并发安全的操作map,可以使用sync.Map结构,sync.Map 是一个适合读多写少的数据结构,今天我们来看看它的设计思想,来看看为什么说它适合读多写少的场景。 如下,是golang 中sync.Map的数据结构…