2023.10.8 基本 Thread 线程详解

news2024/11/17 1:39:26

目录

Thread 常见构造方法

Thread 常见属性

创建一个 Thread 线程 

使用 jconsole 命令观察线程

中断一个 Thread 线程 

等待一个 Thread 线程 

休眠当前  Thread 线程 

让出当前 Thread 线程的 CPU 资源

线程的状态 


Thread 常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象并命名(可重名)
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象并命名
Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组(了解即可)

注意:

  • 当线程被创建时,如果程序员不主动为其命名,JVM 将默认命名为 thread-0、 thread-1、 thread-2 等
  • 主动为线程命名最大的目的就是为了方便程序员调试

Thread 常见属性

属性获取方法解释
IDgetId()获取线程的 ID,为线程的唯一标识
名称getName()构造方法中起的名字
状态getState()获取线程的状态
优先级getPriority()获取线程的优先级,优先级可设置,但作用不大
是否后台线程isDaemon()代码中手动创建的线程和 main 默认为前台线程
内核线程是否存活isAlive()Thread 对象 从调用 start 方法到线程 run 方法执行完,isAlive() 为 true
是否被中断isInterrupted()判断线程是否被中断
返回对象引用currentThread()返回当前线程对象的引用

创建一个 Thread 线程 


可点击下方链接了解 7种创建线程 的方法

创建线程的七种方法


  • 此处简单举例 
//先创建一个类 让该类继承 Thread 父类
class MyThread extends Thread {
//    重写 run 方法
    @Override
    public void run() {
        System.out.println("在 run方法中 自定义线程的工作内容");
    }
}

public class ThreadDemo1 {
    public static void main(String[] args) {
//        创建实例t
        Thread t = new MyThread();
//        启动并创建新线程
        t.start();
//        调用 run 方法仅执行 run 方法中的代码,并不会创建一个新线程
//        t.run();
    }
}

注意:

  • 仅调用 start 方法,系统内核才会真正创建一个线程
  • 当 run 方法运行完,内核中的线程会销毁,但是 Thread 对象 t 还会存在

使用 jconsole 命令观察线程

  • 我们需要借助 JDK,JDK 为 Java 开发工具安装包,其中包含很多工具

1.找到 jdk 安装目录并打开 jconsole

2.选择自己创建的程序并建立连接

  • 如果打开该页面,本地进程中啥也没有,我们可以使用管理员方式运行 jconsole 程序

3.选择不安全连接

4.查看线程


测试代码:

class TestThread extends Thread {
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("这是 testThread ");
        }
    }
}

public class ThreadDemo9 {
    public static void main(String[] args) {
        Thread t = new TestThread();
        t.start();
        while (true) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("这是 main");
        }
    }
}

中断一个 Thread 线程 

  • 中断的意思并不是让线程立即停止,而是通知线程,其应该要停止了,是否真的停止取决于线程中的具体代码

方案一

  • 使用标志位来控制线程是否要停止
public class ThreadDemo10 {
    private static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (flag) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();

        Thread.sleep(3000);
//        主线程这里可以随时通过flag 变量的取值 来操作 t 线程是否结束
        flag = false;
    }
}

运行结果:


方案二

  • 使用 Thread 自带的标志位来进行判定
  • 因为使用方案一 自定义变量的方式时,不能即使响应,如果 run 方法中 sleep 休眠的时间比较长,则会大大影响体验感
  • 使用 Thread 自带的标志位可以唤醒 sleep 方法
package Thread;

public class ThreadDemo11 {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        Thread.sleep(3000);
//        哪个对象调用 interrupt 方法就是终止哪个线程
        t.interrupt();
    }
}

运行结果:

  • 该代码为线程t 忽略了中断请求

适当修改 run 方法内部代码

  • 线程t 立即响应中断请求

  • 线程t 等待一定时间后进行中断操作

  • 当然也能加入其他代码,让线程 t 做点收尾工作再进行中断

总结:

  • 中断的意思并不是让线程立即停止,而是通知线程,其应该要停止了,是否真的停止取决于线程中的具体代码
  • sleep 之所以要清除标志位是因为当线程被唤醒后,该线程是否要中断,是立即中断还是稍后中断,由编写代码的程序员自己决定!

等待一个 Thread 线程 

  • 线程是随机进行调度的
  • 等待线程 做的事就是控制两个线程的结束顺序
public class ThreadDemo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t.start();
        System.out.println("join 之前");

//        此处的join 就是让当前的 main 线程来等待 t 线程执行结束(等待 t 的 run 方法执行完)
        t.join();
        System.out.println("join 之后");
    }
}

运行结果:

注意:

  • 如果执行 join 的时候,线程t 已经执行结束了,此时 mian线程 不会发生阻塞,会直接往下执行
  • 相对于上述代码中 join 的无参版本为死等,join 还有两种带参数的版本更常用,为了防止死等带来程序卡死之类的情况
join(long millis)指定一个最大等待时间
join(long millis, int nanos)nanos 参数表示要等待的额外纳秒数,精确度更高

休眠当前  Thread 线程 

  • 让线程休眠,本质上是让该线程不参与系统调度
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException提供更高精确度的休眠
  • 新创建出来的线程一般是放在 就绪队列 中
  • 当操作系统需要调度一个线程来执行时,就会从就绪队列中选一个
  • 当线程调用 sleep 方法时,该线程就会从 就绪队列 进入阻塞队列,暂时不参与 CPU 的调度执行
  • 但是线程的调度是不可控的,当 sleep 一定时间后线程重写回到就绪队列中时,不能保证其立即被 CPU 调度执行,所以该线程实际的休眠时间大于等于参数设置的休眠时间

让出当前 Thread 线程的 CPU 资源

  • 通过 Thread.yield() 方法来暂停当前正在执行的线程(让出当前的 CPU 资源,并执行其他线程)
  • yiled 方法不会改变线程的状态,只是让该线程从 在 CPU 中正在执行 转变为 回到就绪队列中重写排队参与调度
  • 因为线程具有抢占式执行,随机调度的特点
  • yield 方法无法完全保证当前线程能够让出 CPU 资源,因为可能刚进入就绪队列,又被CPU 调度执行了

线程的状态 

  • NEW:创建了 Thread 对象,但是还没调用 start 方法(内核中还未创建对应的 PCB)
  • TERMINATED:表示内核中的 PCB 已经执行完毕,但是 Thread 对象还在,且一个线程只能 start 一次!
  • RUNNABLE:表示可运行的(正在 CPU 上执行的 + 在就绪队列上随时可被调度的)
  • WAITING:特殊的阻塞,调用 wait 方法
  • TIMED_WAITING: 按照一定时间进行阻塞,调用 sleep 方法
  • BLOCKED: 等待锁的时候进入阻塞状态

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

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

相关文章

Nginx 重新编译添加新的模块

编译安装Nginx的时候&#xff0c;有些模块默认并不会安装&#xff0c;比如http_ssl_module&#xff0c;那么为了让Nginx支持HTTPS&#xff0c;必须添加这个模块。 下面讲解如何在已经安装过后再次添加新的模块。 1、找到安装nginx的源码根目录(即安装包存放目录)&#xff0c;…

2023年【G1工业锅炉司炉】考试题及G1工业锅炉司炉模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年G1工业锅炉司炉考试题为正在备考G1工业锅炉司炉操作证的学员准备的理论考试专题&#xff0c;每个月更新的G1工业锅炉司炉模拟考试祝您顺利通过G1工业锅炉司炉考试。 1、【多选题】TSGG0001-2012《锅炉安全技术监…

Potplayer结合cpolar内网穿透实现公网访问群晖WebDAV

把potplayer变成netflix需要几步&#xff1f; ​ 国内流媒体平台的内容让人一言难尽&#xff0c;就算是购买了国外的优秀作品&#xff0c;也总是在关键剧情上删删减减&#xff0c;就算是充了会员&#xff0c;效果如何&#xff1f; 广大网友不得不选择自己找资源下到本地&#x…

剪切板中,经常用到的gpt编程提问

/data/user/0/org.qpython.qpy/files/bin/qpy thon3.sh "/storage/emulated/0/qpython/评论 截图问题1.矩阵2.1.2.1空行问题1.4.5.py" && exit .1.2.1空行问题1.4.5.py" && exit < 时间戳&#xff1a; 时间戳&#xff1a; ("…

springboot 捕获特点异常信息并处理

前端获取效果图 springboot 捕获特点异常信息并处理 import com.one.utils.JSONResult; //JSONResult定义处理结果对象 import org.springframework.web.bind.annotation.ExceptionHandler

Flink开发环境搭建与提交运行Flink应用程序

Flink开发环境搭建与提交运行Flink应用程序 Flink概述环境 Flink程序开发项目构建添加依赖安装Netcat实现经典的词频统计批处理示例流处理示例 Flink Web UI 命令行提交作业编写Flink程序打包上传Jar提交作业查看任务测试 Web UI提交作业提交作业测试 Flink 概述 Apache Flink…

解决Opencv dnn模块无法使用onnx模型的问题(将onnx的动态输入改成静态)

一、问题来源 最近做人脸识别项目&#xff0c;想只用OpenCV自带的人脸检测和识别模块实现&#xff0c;使用OpenCV传统方法&#xff1a;Haar级联分类器人脸检测LBPH算法人脸识别的教程已经有了&#xff0c;于是想着用OpenCV中的dnn模块来实现&#xff0c;dnn实现人脸检测也有&a…

大数据安全 | 【实验】DES加密解密

文章目录 &#x1f4da;DES介绍&#x1f4da;基本流程&#x1f407;初始IP置换和逆置换&#x1f407;计算每一轮的子密钥&#x1f407;迭代与F函数⭐️E扩展置换⭐️S盒压缩⭐️P盒置换⭐️最后的F函数及迭代实现 &#x1f4da;DES加密解密实现&#x1f4da;关于雪崩效应 &…

企业如何实现信息化管理?IT运维管理有什么注意的事项?

随着信息技术的迅猛发展&#xff0c;企业所面临的IT运维管理挑战也日益复杂。在复杂的IT系统中&#xff0c;如何实施有效的运维管理已成为企业信息化部门关注的重点。本文分析了当前的IT运维管理现状以及所遇到的问题&#xff0c;并提出相应的解决方案——“的修”运维工单管理…

点云处理开发测试题目 完整解决方案

点云处理开发测试题目 文件夹中有一个场景的三块点云数据,单位mm。是一个桌子上放了一个纸箱,纸箱上有四个圆孔。需要做的内容是: 1. 绘制出最小外接立方体,得到纸箱的长宽高值。注意高度计算是纸箱平面到桌子平面的距离。 2. 计算出纸箱上的四个圆的圆心坐标和半径,对圆…

活动聊天机器人如何革新活动行业

在如今快节奏的时代&#xff0c;活动策划和管理对于任何活动的成功变得至关重要。无论是会议、展览会还是企业聚会&#xff0c;组织者都努力为参与者创造难忘的体验&#xff0c;同时确保幕后的顺利执行。然而&#xff0c;由于有许多任务需要处理且资源有限&#xff0c;管理活动…

2023年另类数据研究报告

第一章 引言 1.1 定义 另类数据&#xff0c;通常被定义为传统金融报告和宏观经济指标之外的信息&#xff0c;近年来在投资领域中的重要性日益增长。这种数据通常来源于非传统的数据源&#xff0c;例如社交媒体、卫星图像、互联网搜索记录和消费者交易数据等。与传统数据相比…

docker入门加实战—从部署MySQL入门docker

docker入门加实战—从部署MySQL入门docker docker部署MySQL 输入如下命令&#xff1a; docker run -d \--name mysql \-p 3306:3306 \-e TZAsia/Shanghai \-e MYSQL_ROOT_PASSWORD123 \mysql部署成功截图如下&#xff1a; 当执行命令后&#xff0c;Docker做的第一件事情&…

MAX插件CGMAGIC一键解决效果图在软包硬包上费时费力操作!

使用3dmax软件进行室内建模中的软包、硬包、欧式真皮沙发等家具建模这些的操作相对是比较多的&#xff0c;3dmax软包建模来说&#xff0c;进行手动建模一向都是非常头痛和耗时的事情。 CGMAGIC小编来和大家聊聊&#xff0c;如何一键解决效果图在软包硬包上费时费力操作&#xf…

mp4音视频分离技术

文章目录 问题描述一、分离MP3二、分离无声音的MP4三、结果 问题描述 MP4视频想拆分成一个MP3音频和一个无声音的MP4文件 一、分离MP3 ffmpeg -i C:\Users\Administrator\Desktop\一个文件夹\我在财神殿里长跪不起_完整版MV.mp4 -vn C:\Users\Administrator\Desktop\一个文件…

在XShell里Linux服务器创建和删除子用户

文章目录 在XShell里Linux服务器创建和删除子用户1、创建子用户2、删除子用户 在XShell里Linux服务器创建和删除子用户 1、创建子用户 注意&#xff1a;只有root用户下才能创建子用户 步骤&#xff1a; 首先打开XShell登录上root用户&#xff0c;然后输入useradd 要添加的用户…

SpringBoot-黑马程序员-学习笔记(三)

目录 30.springboot整合MyBatis-plus 32.SSM整合 38.MP中的条件查询 小知识&#xff1a;许多放在类前面的注解&#xff0c;比如Mapper,Service都是将该类定义成一个Bean&#xff0c;交给spring管理 39.Service模块 30.springboot整合MyBatis-plus 1.创建普通springboot项目…

简单大方的自我介绍 PPT 格式

自我介绍是展示自己的机会&#xff0c;同时也是展现自信和魅力的重要时刻。通过简单大方的PPT格式&#xff0c;可以更好地展示自己的个性和才华。下面是一些建议&#xff0c;帮助你在自我介绍中展现自信和魅力。 1. 打造简洁而有吸引力的PPT布局&#xff1a; - 选择简洁大方的背…

牛客 day2 - 7

9.25 day 2 1. 简述方法重写与方法重载的意义与区别&#xff1a; 方法重写&#xff1a; 1.参数列表必须完全与被重写方法相同 //参数列表&#xff08;分为四种&#xff09;&#xff1a; &#xff08;1&#xff09;无参无返回值方法&#xff1b; &#xff08;2&#xff0…

视频监控系统EasyCVR如何通过API接口获取国标GB28181协议接入的实时录像?

安防监控视频汇聚平台EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等功能。平台也提供丰富的API接口供开发者集成、调用…