Thread类的常用方法

文章目录

  • 二. Thread类及常见方法
    • 2.1 常见构造方法
    • 2.2 Thread 的几个常见属性
    • 2.3 启动一个线程 start()
    • 2.4 终止一个线程
    • 2.5 等待一个线程 join()
    • 2.6 获取当前线程的引用
    • 2.7 休眠当前线程

二. Thread类及常见方法

2.1 常见构造方法

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

Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread(new Runnable() {
    @Override
    public void run() {
		//
    }
});

Thread t4 = new Thread("这是我的名字");

Thread t5 = new Thread(new MyRunnable(), "这是我的名字");
Thread t6 = new Thread(new Runnable() {
    @Override
    public void run() {
		//
    }
}, "这是我的名字");

2.2 Thread 的几个常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID是线程的身份标识(JVM给线程设定的标识)
  • 名称是各种调试工具用到
  • 状态表示线程当前所处的一个情况
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
    • 后台线程也称为守护线程, 不影响进程的结束
    • 前台线程, 会影响到进程的结束, 如果前台线程没执行完进程, 是不会结束的.
    • 一个进程中所有的前台线程都执行完并退出了, 即使后台线程没有执行完, 也会跟着进程一起推出.
  • 是否存活,即简单的理解,为 run 方法是否运行结束了

2.3 启动一个线程 start()

调用start()方法才能在操作系统中创建出一个线程.

调用完start方法后, 代码会立即继续执行start后续的逻辑.

2.4 终止一个线程

当一个线程的run方法执行完毕, 线程就算终止了. 此处的终止线程, 就是让run能够尽快的执行完毕.

如何使其尽快结束?

  • 手动设定标志位.

    public class Demo {
        public static boolean isQuit = false;//标志位
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                while (!isQuit) {
                    System.out.println("Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            });
            t.start();
            //主线程这里执行一些其他逻辑之后, 让t线程结束
            
            Thread.sleep(3000);
            isQuit = true;//修改标志位
            System.out.println("t线程终止");
        }
    }
    

    在这里插入图片描述

    如果我们把代码改成这样

    public class Demo {
        public static void main(String[] args) throws InterruptedException {
            boolean isQuit = false;//标志位
            Thread t = new Thread(() -> {
                while (!isQuit) {
                    System.out.println("Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            });
            t.start();
            //主线程这里执行一些其他逻辑之后, 让t线程结束
            
            Thread.sleep(3000);
            isQuit = true;//修改标志位
            System.out.println("t线程终止");
        }
    }
    

    编译器会报错, 为什么?

    因为我们创建线程借用的是lambda表达式, 他是一个回调函数, 只有时机到了才会执行, 所以他的执行时间是靠后的, 这就导致后续真正执行lambda的时候, 局部变量isQuit可能已经被摧毁了.

    所以让lambda去访问一个已经被销毁的变量是不合适的.

    lambda便引入了"变量捕获"这样的机制 : lambda内部看起来是在直接访问外部的变量, 其实本质上是吧外部的变量给复制一份到lambda里面, 这样就解决生命周期的问题了.

    但是, 变量捕获有个限制, 要求捕获的变量final的, 即不可变的. 而上述代码在主线程内修改了被捕获变量的值, 所以报错了.

    我们的第一种写法没有触发变量捕获, 而是内部类访问外部类的成员, 这种写法是合理的.

  • 使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定

    义标志位.

    public class Demo {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
            Thread.sleep(3000);
            t.interrupt();
            System.out.println("0");
        }
    }
    
    • Thread.currentThread(): 获取到当前的Thread对象. 在代码中就相当于t, 为什么不直接用t呢? 因为lambda表达式是在构造t之前就定义好的, 如果直接用t就会使编译器认为他是一个还没初始化的对象.

    • isInterrupted(): Thread对象内部提供了一个标志位(boolean), 若方法返回true, 则表示线程应该结束, 若是false, 线程先不必结束.

    • interrupt(): 把标志为设置成true.

    • 如果运行上述代码, 会爆出一个异常, 并且循环不会终止

      在这里插入图片描述

      这个异常的意思是, 睡眠时被唤醒. 在被唤醒后, 标志位会被自动清除, 如果还想让线程停止, 直接在catch里面加个break即可.

    • 当sleep被唤醒后, 可以有以下几种操作方式

      • 立即结束线程: 在catch中直接break.
      • 继续做其他事情, 一会在结束线程: 在catch中执行别的逻辑, 执行完了再break.
      • 忽略终止请求, 继续执行该线程: 不写break.

2.5 等待一个线程 join()

有时, 我们需要等待一个线程完成它的工作后, 才能进行自己的下一步工作. 例如, 张三只有等李四转账成功, 才决定是否存钱, 这时我们需要一个方法明确等待线程的结束.

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)同理,但可以更高精度

a, b两个线程, 希望b先结束, a后结束, 就可以在a线程中调用b.join方法. 如果b县城还没执行完, a线程会进入阻塞状态. b执行完后, a再从阻塞状态中恢复回来, 继续往后执行.

public class Demo {
    public static void main(String[] args) {
        Thread b = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("b");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("b end");
        });
        Thread a = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println("a");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                b.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("a end");
        });

        a.start();
        b.start();
    }
}

2.6 获取当前线程的引用

方法说明
public static Thread currentThread();返回当前线程对象的引用

2.7 休眠当前线程

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis毫秒
public static void sleep(long millis, int nanos) throws InterruptedException可以更高精度的休眠

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

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

相关文章

C语言每日一题:11.《数据结构》链表分割。

题目一&#xff1a; 题目链接&#xff1a; 思路一&#xff1a;使用带头链表 1.构建两个新的带头链表&#xff0c;头节点不存储数据。 2.循环遍历原来的链表。 3.小于x的尾插到第一个链表。 4.大于等于x尾插到第二个链表。 5.进行链表合并&#xff0c;注意第二个链表的尾的下一…

RISC-V 指令集介绍

1. 背景介绍 指令集从本质上可以分为复杂指令集&#xff08;Complex Instruction Set Computer&#xff0c;CISC&#xff09;和精简指令集&#xff08;Reduced Instruction Set Computer&#xff0c;RISC&#xff09;两种。复杂指令集的特点是能够在一条指令内完成很多事情。 指…

【外卖系统】分类管理业务

公共字段自动填充 需求分析 对于之前的开发中&#xff0c;有创建时间、创建人、修改时间、修改人等字段&#xff0c;在其他功能中也会有出现&#xff0c;属于公共字段&#xff0c;对于这些公共字段最好是在某个地方统一处理以简化开发&#xff0c;使用Mybatis Plus提供的公共…

iPhone 7透明屏的显示效果怎么样?

iPhone 7是苹果公司于2016年推出的一款智能手机&#xff0c;它采用了4.7英寸的Retina HD显示屏&#xff0c;分辨率为1334x750像素。 虽然iPhone 7的屏幕并不是透明的&#xff0c;但是苹果公司在设计上采用了一些技术&#xff0c;使得用户在使用iPhone 7时可以有一种透明的感觉…

28.利用fminsearch、fminunc 求解最大利润问题(matlab程序)

1.简述 1.无约束&#xff08;无条件&#xff09;的最优化 fminunc函数 : - 可用于任意函数求最小值 - 统一求最小值问题 - 如求最大值问题&#xff1a; >对函数取相反数而变成求最小值问题&#xff0c;最后把函数值取反即为函数的最大值。 使用格式如下 1.必须预先把函数存…

【Golang 接口自动化08】使用标准库httptest完成HTTP请求的Mock测试

目录 前言 http包的HandleFunc函数 http.Request/http.ResponseWriter httptest 定义被测接口 测试代码 测试执行 总结 资料获取方法 前言 Mock是一个做自动化测试永远绕不过去的话题。本文主要介绍使用标准库net/http/httptest完成HTTP请求的Mock的测试方法。 可能有…

113、单例Bean是单例模式吗?

单例Bean是单例模式吗? 通常来说,单例模式是指在一个JVM中,一个类只能构造出来一个对象,有很多方法来实现单例模式,比如懒汉模式,但是我们通常讲的单例模式有一个前提条件就是规定在一个JVM中,那如果要在两个JVM中保证单例呢?那可能就要用分布式锁这些技术,这里的重点…

性能测试基础知识(三)性能指标

性能测试基础知识&#xff08;三&#xff09;性能指标 前言一、时间特性1、响应时间2、并发数3、吞吐量&#xff08;TPS&#xff09; 二、资源特性1、CPU利用率2、内存利用率3、I/O利用率4、网络带宽使用率5、网络传输速率&#xff08;MB/s&#xff09; 三、实例场景 前言 性能…

面试总结(三)

1.进程和线程的区别 根本区别&#xff1a;进程是操作系统分配资源的最小单位&#xff1b;线程是CPU调度的最小单位所属关系&#xff1a;一个进程包含了多个线程&#xff0c;至少拥有一个主线程&#xff1b;线程所属于进程开销不同&#xff1a;进程的创建&#xff0c;销毁&…

LViT:语言与视觉Transformer在医学图像分割

论文链接&#xff1a;https://arxiv.org/abs/2206.14718 代码链接&#xff1a;GitHub - HUANGLIZI/LViT: This repo is the official implementation of "LViT: Language meets Vision Transformer in Medical Image Segmentation" (IEEE Transactions on Medical I…

华为数通HCIP-IGMP(网络组管理协议)

IGMP&#xff08;网络组管理协议&#xff09; 作用&#xff1a;维护、管理最后一跳路由器以及组播接收者之间的关系&#xff1b; 应用&#xff1a;最后一跳路由器以及组播接收者之间&#xff1b; 原理&#xff1a;当组播接收者需要接收某个组别的流量时&#xff0c;会向最后…

SpringCloud Gateway 在微服务架构下的最佳实践

作者&#xff1a;徐靖峰&#xff08;岛风&#xff09; 前言 本文整理自云原生技术实践营广州站 Meetup 的分享&#xff0c;其中的经验来自于我们团队开发的阿里云 CSB 2.0 这款产品&#xff0c;其基于开源 SpringCloud Gateway 开发&#xff0c;在完全兼容开源用法的前提下&a…

数据结构-链表

&#x1f5e1;CSDN主页&#xff1a;d1ff1cult.&#x1f5e1; &#x1f5e1;代码云仓库&#xff1a;d1ff1cult.&#x1f5e1; &#x1f5e1;文章栏目&#xff1a;数据结构专栏&#x1f5e1; 目录 目录 代码总览&#xff1a; 接口slist.h&#xff1a; slist.c: 1.什么是链表 1.1链…

消息触达平台 - 基础理论

目录 消息触达平台 背景 业务流程 触达配置 服务处理 表现展示 效果统计 触达信息结构 对象 内容 渠道 场景 机制 消息触达平台 背景 在产品生命周期的不同阶段&#xff0c;用户触达体系可以用来对不同用户群体进行定制化运营。结合咱们的日常场景&#xff0c;公司的运营同学或…

【前端知识】React 基础巩固(四十一)——手动路由跳转、参数传递及路由配置

React 基础巩固(四十一)——手动路由跳转、参数传递及路由配置 一、实现手动跳转路由 利用 useNavigate 封装一个 withRouter&#xff08;hoc/with_router.js&#xff09; import { useNavigate } from "react-router-dom"; // 封装一个高阶组件 function withRou…

vue + element UI Table 表格 利用插槽是 最后一行 操作 的边框线 不显示

在屏幕比例100%时 el-table添加border属性 使用作用域插槽 会不显示某侧的边框线&#xff0c;屏幕比例缩小或放大都展示 // 修复列的 边框线消失的bug thead th:not(.is-hidden):last-child {right:-1px;// 或者//border-left: 1px solid #ebeef5; } .el-table__row{td:not(.i…

常用的CSS渐变样式

边框渐变 方案1&#xff1a; 边框渐变( 支持圆角) width: 726px;height: 144px;border-radius: 24px;border: 5px solid transparent;background-clip: padding-box, border-box; background-origin: padding-box, border-box; background-image: linear-gradient(to right, #f…

RabbitMQ 教程 | 第4章 RabbitMQ 进阶

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

基于多线程实现服务器并发

看大丙老师的B站视频总结的笔记19-基于多线程实现服务器并发分析_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1F64y1U7A2/?p19&spm_id_frompageDriver&vd_sourcea934d7fc6f47698a29dac90a922ba5a3 思路&#xff1a;首先accept是有一个线程的&#xff0c;另外…