JavaEE——多线程Thread 类及常见方法

news2024/9/28 14:38:52

目录

 

一、Thread(String name)

二、是否后台线程 isDeamon()

三、是否存活 isAlive()

四、run()方法和start()方法的区别

五、中断线程

法一:

法二:

六、线程等待join()

七、线程休眠sleep()

一、Thread(String name)

定义:这个东西是给线程(thread 对象) 起一个名字。起一个啥样的名字,不影响线程本身的执行,仅仅只是影响到程序猿调试可以借助一些工具看到每个线程以及名字.很容易在调试中对线程做出区分。

那么如何查看线程的名字呢?这里jdk本身就自带了一个程序叫做jconsole可以用来查看本地进程。

那么首先先在我们自己idea里面创建一个线程demo8,右键运行,代码如下:

public class demo8 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true){
                System.out.println("hello 1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"T1");
        t1.start();
 
        Thread t2 = new Thread(() -> {
            while (true){
                System.out.println("hello 2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"T2");
        t2.start();
    }
}

二、是否后台线程 isDeamon()

什么是后台线程呢?

如果线程是后台线程,就不影响 进程退出如果线程不是后台线程(前台线程),就会影响到进程退出。
创建的 t1 和 t2 默认都是前台的线程。
即使 main 方法执行完毕,进程也不能退出.得等 t1 和 t2 都执行完,整个进程才能退出!!!如果 t1 和 t2 是后台线程此时如果 main 执行完毕,整个进程就直接退出,t1 和 t2 就被强行终止了。

三、是否存活 isAlive()

这个属性的意思就是——操作系统中对应的线程是否正在运行
Thread t 对象的生命周期和内核中对应的线程,生命周期并不完全一致~~创建出 t 对象之后,在调用 start 之前,系统中是没有对应线程的~~在 run 方法执行完了之后, 系统中的线程就销毁了但是 t 这个对象可能还存在。通过 isAlive 就能判定当前系统的线程的运行情况。

如果 调用 start 之后, run 执行完之前,isAlive 就是返回 true

如果 调用 start 之前, run 执行完之后, isAlive 就返回 false

四、run()方法和start()方法的区别

1. start() 方法来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕, 可以直接继续执行下面的代码。
2. 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于 就绪状态 , 并没有运 行。
3. 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了 运行状态,开始运 行 run 函数当中的代码 。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。

run 单纯的只是一个普通的方法, 描述了任务的内容。

start 则是一个特殊的方法, 内部会在系统中创建线程。

看一段代码:

run() 方法只是一个普通的方法你在 main 线程里调用 run,其实并没有创建新的线程这个循环仍然是在 main 线程中执行。

之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程 就开始运行了。
覆写 run 方法是提供给线程要做的事情的指令清单
线程对象可以认为是把 李四、王五叫过来了
而调用 start() 方法,就是喊一声: 行动起来! ,线程才真正独立去执行了。
调用 start 方法 , 才真的在操作系统的底层创建出一个线程 .

五、中断线程

中断线程的意思就是让一个线程停下来!

线程停下来的关键,是要让线程对应的 run 方法执行完(还有一个特殊的,是 main 这个线程对于 main 来说,得是 main 方法执行完,线程就完了)。

法一:通过共享的标记来进行沟通

手动设置一个标志位。
看一段代码:我们在这个代码里面创建一个标志位isquit,通过while(!isquit)来判断循环是否结束,可以通过手动的设置isquit的值来控制线程的结束与否。为什么在其他线程中修改isquit的值可以影响到当前线程呢?此处因为,多个线程共用同一个虚拟地址空间!!因此, main 线程修改的 isquit 和 t 线程判定的 isquit, 是同一个值。

public class demo10 {
    public static  boolean isquit = false;
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while(!isquit){
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        //只要把这个isquit设置为true,进一步的run就执行完了,再进一步就是线程执行结束了。
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isquit = true;
        System.out.println("终止线程!");
    }
}

那么像刚才那种写法并不够严谨,我们可以参考第二种写法。

.

法二: 调用 interrupt() 方法来通知

使用Thread中内置的标志位来判定。
我们可以通过:
Thread.interrupted()—— 一个静态的方法。
Thread.currentThread0.islnterrupted()—— 实例方法.

其中 currentThread 能够获取到当前线程的实例。

看新的代码段:

public class demo11 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("hello thread!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //当触发异常之后 立刻退出循环
                    break;
                }
            }
        });
        t.start();
 
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        t.interrupt();
    }
}

那么使用这种方法的原因就是——这个代码绝大部分情况,都是在休眠状态阻塞,此处的中断,是希望能够立即产生效果。如果线程已经是阻塞状态下,此时设置标志位就不能起到及时唤醒的效果

异常处理方式:调用这个 interrupt 方法, 就会让 sleep 触发一个异常从而导致 线程从阻塞状态被唤醒。

+

 当下的代码,一旦触发了异常之后, 就进入了 catch 语句.在catch中,就单纯的只是打了一个日志
printStackTrace 是打印当前出现异常位置的代码调用栈,打完日志之后,就直接继续运行。

我们可以发现在代码的最后我们调用了interrupt()方法,那么调用这个方法可能产生两种情况。

1、如果t线程处在就绪状态,就是设置线程的标志位为true

2、如果t线程处在阻塞状态,就会触发一个InterruptException。

Thread.currentThread0.islnterrupted()—— 实例方法.

这个方法判定的标志位是 Thread 的普通成员,每个示例都有自己的标志位,所以一般无脑使用这个方法即可。

六、线程等待join()

在我们的日常开发中,因为线程之间的调度顺序是按照调度器来安排的,这个过程是随机,无序的,我们希望能够控制多个线程之间的调度顺序,那么线程等待就是一种方式。

要想实现线程等待这里会使用到一个函数叫做join(),即哪个线程调用join哪个线程就会进入阻塞状态。

代码演示:

public class demo12 {
    public static void main(String[] args) {
        Thread t = new Thread(() ->{
            for (int i = 0; i < 5; i++) {
                System.out.println("hello thread!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
 
        //在主线程中就可以使用一个等待操作,来等待t线程执行结束。
        try {
            t.join(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们可以看到在代码的后面出现了这么一行代码  t.join(10000);这里的意思就是让main线程等待t线程的run方法执行完毕,等待时间是10000ms。

七、线程休眠sleep()

这个线程休眠这里就不在过多赘述了,因为之前的案例中已经出现了很多的实例调用了sleep()方法。这里介绍一下进程中各个线程之间的关系。

进程是由PCB + 双向链表组成。这个说法是针对只有一个线程的进程,是如此的。
如果是一个进程有多个线程, 此时每个线程都有一个 PCB一个进程对应的就是一组 PCB 了。PCB 上有一个字段 tgroupld,这个 id 其实就相当于进程的 id.同一个进程中的若干个线程的 tgroupld 是相同的。

即某个线程调用了sleep()方法,PCB就会进入阻塞队列,操作系统调度线程的时候,就只是从就绪队列中挑选合适的 PCB到 CPU 上运行。阻塞队列里的 PCB 就只能干等着。

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

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

相关文章

免杀对抗—C++混淆算法shellcode上线回调编译执行

前言 上次讲了python混淆免杀&#xff0c;今天讲一下C混淆免杀。其实都大差不差的&#xff0c;也都是通过各种算法对shellcod进行混淆免杀&#xff0c;只不过是语言从python换成c了而已。 实验环境 测试环境依旧是360、火绒、WD还有VT。 shellcode上线 下面是最基本几个sh…

数据恢复篇:如何恢复几年前删除的照片

您是否曾经遇到过几年前删除了一张图片并觉得需要恢复旧照片的情况&#xff1f;虽然&#xff0c;没有确定的方法可以丢失或删除的照片。但是&#xff0c;借助奇客数据恢复等恢复工具&#xff0c;可以恢复多年前永久删除的照片、视频和音频文件。 注意 – 如果旧数据被覆盖&…

差速轮纯跟踪算法

fig.1 差速轮纯跟踪原理图 纯跟踪是基于几何关系的跟踪控制算法&#xff0c;不管是阿克曼模型&#xff0c;还是差速轮模型&#xff0c;都是控制机器驱动轮&#xff08;通常是后轮&#xff09;中心经过目标点 T。 基于机器驱动轮中心&#xff0c;车头朝向为 X 轴正方向&#xf…

ESP32 Bluedroid 篇(1)—— ibeacon 广播

前言 前面我们已经了解了 ESP32 的 BLE 整体架构&#xff0c;现在我们开始实际学习一下Bluedroid 从机篇的广播和扫描。本文将会以 ble_ibeacon demo 为例子进行讲解&#xff0c;需要注意的一点是。ibeacon 分为两个部分&#xff0c;一个是作为广播者&#xff0c;一个是作为观…

小徐影院:Spring Boot影院管理新体验

第三章 系统分析 整个系统的功能模块主要是对各个项目元素组合、分解和更换做出对应的单元&#xff0c;最后在根据各个系统模块来做出一个简单的原则&#xff0c;系统的整体设计是根据用户的需求来进行设计的。为了更好的服务于用户要从小徐影城管理系统的设计与实现方面上做出…

24年下重庆事业单位考试报名超详细流程

&#x1f388;提交报考申请 考生通过重庆市人力资源和社会保障局官网&#xff08;rlsbj.cq.gov.cn&#xff09;“热点服务”中“人事考试网上报名”栏进行报名。报名时间为2024年8月12日9:00—8月17日9:00。 &#x1f388;网上缴费 资格初审合格后&#xff0c;考生应在2024年8…

【Python】1.初始Python--打开Python的大门

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

数据结构:排序(内部排序+各种排序算法的性质总结)

数据结构的排序是计算机科学中的一个基本且重要的操作&#xff0c;它指的是将一组数据元素&#xff08;或记录&#xff09;按照一定规则&#xff08;通常是关键字的大小&#xff09;进行排列的过程。排序后的数据元素在物理或逻辑上呈现出某种顺序性&#xff0c;从而便于后续的…

GPIO端口的使用

目录 一. 前言 二. APB2外设时钟使能寄存器 三. GPIO端口的描述 四. GPIO端口使用案例 一. 前言 基于库函数的开发方式就是使用ST官方提供的封装好的函数。而如果没有添加库函数&#xff0c;那就是基于寄存器的开发方式&#xff0c;这种方式一般不是很推荐。因为由于ST对寄存…

华为-IPv6与IPv4网络互通的6to4自动隧道配置实验

IPv4向IPv6的过渡不是一次性的,而是逐步地分层次地。在过渡时期,为了保证IPv4和IPv6能够共存、互通,人们发明了一些IPv4/IPv6的互通技术。 本实验以6to4技术为例,阐述如何配置IPv6过渡技术。 配置参考 R1 # sysname R1 # ipv6# interface GigabitEthernet0/0/1ip address 200…

Java程序的控制结构

1、分支语句 1.1、if语句 if语句的三种格式 &#xff08;1&#xff09;单分支语句(if...) 格式&#xff1a;if&#xff08;表达式&#xff09;{ 语句 } 例&#xff1a;两个数比较最大值 int a3,b9; int maxa; if(b>max){System.out.println(max) } &#xff08;2&#x…

你要的录音播放录音功能,直接用!—Air201资产定位模组LuatOS

超低功耗、精准定位、快速量产——迷你小巧的合宙Air201&#xff0c;正给越来越多的行业客户带来高效开发体验。 此前有小伙伴问&#xff1a;是否支持录音、播放录音功能&#xff1f; 高集成化设计的Air201自带了ES8311音频解码芯片&#xff08;Audio Codec&#xff09;及MIC…

2. PH47代码框架二次开发功能特性

2.1. 概述 PH47代码框架为二次开发用户提供了丰富的&#xff0c;面向无人机飞行控制以及其他运动控制领域的功能特性&#xff0c;依托这些预设的功能特性&#xff0c;用户能够在短时间内开发出具体具备强大功能及可靠性的二次开发应用。此章节主要对二次开发特性进行了详细描述…

sentinel原理源码分析系列(一)-总述

背景 微服务是目前java主流开发架构&#xff0c;微服务架构技术栈有&#xff0c;服务注册中心&#xff0c;网关&#xff0c;熔断限流&#xff0c;服务同学&#xff0c;配置中心等组件&#xff0c;其中&#xff0c;熔断限流主要3个功能特性&#xff0c;限流&#xff0c;熔断&…

云原生之运维监控实践-OpenEuler22.03SP3上安装Prometheus与Grafana实现主机状态监测

背景 如果没有监控&#xff0c;那么最好的情况是没有问题发生&#xff0c;最糟糕的情况则是问题发生了但没有被发现。——《Prometheus监控实战》 去年写了一篇在Docker环境下部署若依微服务ruoyi-cloud项目的文章&#xff0c;当时使用的是 docker-compose 在单台机器上部署若依…

NutUI 单元测试:从 jest 到 vitest

NutUI Vue 自 3.0 版本起&#xff0c;开始使用 vite 作为项目的构建工具&#xff0c;单元测试工具则依然使用 jest。而后 vite 官方团队开源了 vitest 作为 vite 的首选测试框架和 jest 的替代品。 本文主要介绍 NutUI 从 jest 到 vitest 的迁移过程&#xff0c;以及后续对于单…

电商系统开发全攻略:基于Spring Boot的在线商城

2 相关技术 2.1 Springboot框架介绍 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Spring…

Go 项目开发常用设计模式

设计模式就某些编码场景下的最佳实践&#xff0c;用来解决常见的软件设计问题。Go 语言不是面向对象语言&#xff0c;但是可以使用结构体、接口等类型实现面向对象语言的特性&#xff0c;想要弄懂设计模式&#xff0c;要熟练的使用 Go 语言接口类型 和结构体类型 设计模式总体上…

关于Chrome浏览器F12调试,显示未连接到互联网的问题

情况说明 最近笔者更新下电脑的Chrome浏览器&#xff0c;在调试前端代码的时候&#xff0c;遇到下面一个情况&#xff1a; 发现打开调试面板后&#xff0c;页面上显示未连接到互联网&#xff0c;但实际电脑网络是没有问题的&#xff0c;关闭调试面板后&#xff0c;网页又能正…

Python 爬虫 根据ID获得UP视频信息

思路&#xff1a; 用selenium库对网页进行获取&#xff0c;然后用bs4进行分析&#xff0c;拿到bv号&#xff0c;标题&#xff0c;封面&#xff0c;时长&#xff0c;播放量&#xff0c;发布时间 先启动webdriver.&#xff0c;进入网页之后&#xff0c;先等几秒&#xff0c;等加…