【JavaEE】多线程(二)Thread 类及常见方法

news2025/2/4 3:58:39

✨哈喽,进来的小伙伴们,你们好耶!✨

🛰️🛰️系列专栏:【JavaEE】

✈️✈️本篇内容:Thread类再剖析!

🚀🚀代码存放仓库gitee:JavaEE初阶代码存放!

⛵⛵作者简介:一名双非本科大三在读的科班Java编程小白,道阻且长,星夜启程!

目录

 一、Thread(String name)

二、是否后台线程 isDeamon()

三、是否存活 isAlive()

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

五、中断线程

法一:手动设置一个标志位。

法二:使用Thread中内置的标志位来判定。

六、线程等待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();
    }
}

运行结果:

查看线程步骤如下:

1、首先找到我们的电脑安装jdk的位置,这里给大家展示一下博主本人的电脑jdk路径下的jconsole位置。

2、 ok,那么找到这个jconsole程序我们直接双击打开就可以查看我们电脑的本地进程:

jconsole 这里能够罗列出你系统上的 java 进程,上图红色圈起来的部分从上往下依次对应的线程是自己在idea里面创建的线程demo8IDEAjconsole本身

3、双击我们自己创建的线程demo8,可以看到是下面这张图片的样式,因为我们电脑自带防火墙系统,所以直接点击不安全的连接即可。

 4、进来之后我们点击线程这一列,就可以看到我们创建的线程t1,t2。

可以看到,当我们的java线程一启动,这里面还有一些其他的线程,这些显示是jvm自己创建的用来处理一些其他的任务。

二、是否后台线程 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()方法的区别

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

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

看一段代码:

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

五、中断线程

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

线程停下来的关键,是要让线程对应的 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("终止线程!");
    }
}

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

法二:使用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/103583.html

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

相关文章

对记录做横向分栏

【问题】 Hi i have a single list of employees. Each employee will have his name and salary. i have given the list of employees to a table but it appears as follows Employee Name Salary harish 3000 kiran 4000 Emili 6000 h…

Jenkins(2)— 配置webhook触发器

1、webhook介绍 Gitee WebHook触发器 的功能是帮助用户 push 代码后&#xff0c;自动回调一个您设定的 http 地址。例如我们可以通过添加webhook触发器来实现这样一个功能&#xff1a; 每当开发push代码到提测分支后&#xff0c;自动触发jenkins构建&#xff0c;运行自动化测…

闲暇之际敲敲代码,记录Leetcode刷题03

文章目录前言一、删除链表中的节点1.1 问题描述1.2 思路分析二、反转链表2.1 问题描述2.2 思路分析前言 利用闲暇之际敲敲代码&#xff0c;提升编程技能及提高算法能力。 一、删除链表中的节点 1.1 问题描述 有一个单链表的 head&#xff0c;我们想删除它其中的一个节点 no…

Tensorflow基础入门超全总结

1.1 TensorFlow介绍 深度学习框架TensorFlow一经发布&#xff0c;就受到了广泛的关注&#xff0c;并在计算机视觉、音频处理、推荐系统和自然语言处理等场景下都被大面积推广使用&#xff0c;现在已发布2.3.0版本&#xff0c;接下来我们深入浅出的介绍Tensorflow的相关应用。 …

记录一个阿里云Android端文件上传的BUG

背景 Android移动端需要接入阿里云视频点播模块下的一个客户端上传的SDK。需要将移动端本地文件上传至阿里云服务器。 问题描述 调用方法及业务逻辑不赘述&#xff0c;贴张官方图&#xff0c;选择了上传地址和凭证的方法进行上传&#xff0c;并且是后台集成点播服务端SDK并调用…

关于哈希表

package com.javase.map.hashmap;import java.util.HashMap; import java.util.Map; import java.util.Set;/*** 关于HashMap&#xff1a;* 1.HashMap集合的底层是哈希表/散列表的数据结构。* 2.哈希表是数组和单向链表的结合体&#xff0c;充分发挥了它们各自的优点。…

【机器学习】三种主要集成学习思想简介

集成学习 集成学习通过训练多个分类器,然后将其组合起来,从而达到更好的预测性能,提高分类器的泛化能力。 目前集成学习有3个主要框架:bagging、boosting、stacking。 bagging套袋法 bagging是并行集成学习方法的最著名代表,其算法过程如下: 从原始样本集中抽取训练…

【云原生进阶之容器】第一章Docker核心技术1.8节——DockerFile解析

1 Dockfile详解 1.1 什么是Dockerfile 首先通过一张图来了解 Docker 镜像、容器和 Dockerfile 三者之间的关系。 通过上图可以看出使用 Dockerfile 定义镜像,运行镜像启动容器。 Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文…

技术分享 | 黑盒测试方法论—场景法

场景法就是模拟用户操作软件时的场景&#xff0c;主要用于测试系统的业务流程。 测试不能只关注某个控件的边界值、等价类是否满足要求&#xff0c;也要关注它的主要功能和业务流程是否正确实现&#xff0c;这时就需要使用场景法来完成。 场景法 用例场景是用来描述流经用例路…

OpenHarmony 物联网设备开发环境搭建

前言 我们介绍的是华为官方推荐的 Windows + Ubuntu 混合开发的环境,使用Windows平台的DevEco Device Tool 进行可视化界面进行相关操作,通过远程连接的方式对接Ubuntu下的DevEco Device Tool,然后对Ubuntu下的源码进行开发、编译、烧录等操作。 目前官方不支持Mac系统,所…

【docker】什么是容器数据卷?

docker的理念回顾 将应用和环境打包成一个镜像&#xff01; 数据&#xff1f;如果数据都在容器中&#xff0c;那么我们容器删除&#xff0c;数据就会丢失&#xff01;需求&#xff1a;数据可以持久化 MySQL&#xff0c;容器删了&#xff0c;删库跑路&#xff01;需求&#x…

测试工具平台 MeterSphere 分享

一、官网地址 meterSphere 二、安装方式 Linux安装 默认账号密码&#xff1a; URL: http://$LOCAL_IP:8081用户名: admin初始密码: metersphere三、nginx配置 直接上配置 location / {proxy_pass http://localhost:8081;client_max_body_size 1000m;#access_log off;# 配…

SPDK代码结构浅析

最近这三周时间一直因为工作的需要在研究SPDK移植到RISCV平台上&#xff0c;在编译通过的时候&#xff0c;也顺带把SPDK的代码粗粗过了一遍&#xff0c;顺便做了一点笔记。 SPDK (Storage Performance Development Kit)其实就是在用户空间&#xff0c;采用轮询的方式无锁的NVM…

通达信下单接口获取指数成份股的步骤分享

通达信下单接口获取指数成份股的步骤分享&#xff1a; ContextInfo.get_sector() 接口&#xff1a;https://gitee.com/metatradeapi 用法&#xff1a; ContextInfo.get_sector(sector, realtime) 释义&#xff1a; 获取板块成份股&#xff0c;只支持取指数成份股 参数&…

DOM学习笔记(坚持~~~~)

1.DOM简介 1.1什么是DOM 文档对象模型简称DOM&#xff0c;W3C组织推荐的处理可扩展标记语言的标准编程接口&#xff0c;通过这些DOM接口可以改变网页的内容&#xff0c;结构和样式。 1.2 DOM树 文档&#xff1a;一个页面就是一个文档&#xff0c;DOM中使用document表示 元素&…

Python+Qt身体特征识别人数统计源码窗体程序

程序示例精选 PythonQt身体特征识别人数统计 如需安装运行环境或远程调试&#xff0c;见文章底部微信名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PPythonQt身体特征识别人数统计》编写代码&#xff0c;功能包括了相片&#xff0c;摄像头身体识别…

Javaweb中的Request(请求)和Response(响应)

目录 一、概念 二、请求&#xff08;Request&#xff09; 1.例子简介 2.Request继承体系 3.Request获取请求数据 &#xff08;1&#xff09;请求行 &#xff08;2&#xff09;请求头 &#xff08;3&#xff09;请求体 4.优化请求体参数的获取 5.解决请求参数乱码问…

POSIX Timer

一、特点&#xff1a; 1、使用 POSIX Timer&#xff0c;一个进程可以创建任意多个 Timer。 2、setitmer 计时器时间到达时&#xff0c;可以有多种通知方式&#xff0c;比如信号&#xff0c;或者启动线程。 3、POSIX Timer 则可以使用实时信号。 4、POSIX Timer 是针对有实时要…

leetcode98. 验证二叉搜索树关于递归实现中遇到的global和nonlocal(各种报错分析)

leetcode98. 验证二叉搜索树 题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二…

前端基础(十三)_定位position、定位层级z-index

一、定位position Css的定位机制&#xff1a;普通文档流、浮动、定位 这里主要介绍CSS的定位属性&#xff1a;position&#xff1a; 1、定位原理&#xff1a;允许元素相对于正常位置、或者相对于父元素、浏览器窗口本上的位置 2、元素位置的调整&#xff1a; left|right属性、…