Thread类的常用方法

news2024/12/29 10:50:30

目录

1.Thread类常用的构造方法

2.Thread类的几个常见属性

2.1 什么是守护线程?isDaemon

2.2线程是否存活 isAliye()

3.终止线程的方法

3.1使用共享标志位通知中断线程

3.2使用Thread自带的标志位通知

4.等待线程 join

5.获取当前线程的引用

6.休眠当前线程


Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联

1.Thread类常用的构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建线程对象并命名
Thread(Runnable target,String name)使用Runnable对象创建线程对象并命名

多了个name参数是为了给线程一个名称方便调试线程

我们使用最后一个方法创建对象并且命名,然后再java工具中找到这个name的线程

public class ThreadDemo6 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    System.out.println("hello world!!");
                }
            }
        },"myThread");
        t.start();
    }
}

 

 

 这里就可以看到我们刚刚创建并且命名的线程了,t是代码里面的变量名,myThread是线程名

可以看到这里这里没有main线程了,是因为主线程执行完了start之后就紧接着结束了main方法,对主线程来说,main方法没了,自己也就结束了

同样的,当run方法执行完了,myThread线程也就自动结束了

2.Thread类的几个常见属性

属性获取方法说明

ID

getId()获取到线程的身份标识
名称getName()获取到构造方法中的名字
状态getState()获取到线程的状态(Java中的线程的状态比操作系统的原生的状态更丰富一些)
优先级getPriority()获取或者设置优先级
是否后台线程isDaemon()是否是守护线程
是否存活isAliye()判定线程是否存活
是否被中断isInterrupted()是否被中断

2.1 什么是守护线程?isDaemon

java中的线程分为前台和后台线程,代码里手动创建的线程,Main线程都是前台的线程,其它的JVM自带的线程都是后台的线程,也就是守护线程.

也可以通过setDaemon来手动设置成后台线程

前台线程和后台线程的特点:

前台线程会阻止进程的结束,前台线程的工作没有做完,进程是不能结束的,后台线程不会阻止进程结束,后台工作没做完,进程是可以结束的

刚刚在上面创建的myThread线程默认是前台线程,我们使用 setDaemon来手动设置成后台线程

t线程还没执行完,但是进程直接结束了

 当t被设置成守护线程,那么进程的结束与否就与t没有关系了,此时前台线程只剩下主线程了,主线程什么时候执行完,进程什么时候结束

2.2线程是否存活 isAliye()

 回顾一下线程是如何被创建的

 因此,在调用start()之前调用isAliye()结果应该是false,调用start()之后调用isAliye()结果应该是true.

isAliye()是在判断当前系统里的线程是否是真的创建了,如果内核中的线程把run()执行完了,PCB释放了,但是t这个对象不一定被释放,此时isAliye()被调用后还是false

也可以看出t这个对象的生命周期,是比内核中的PCB生命周期长的

下面看代码演示:

public class ThreadDemo6 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world!!");
            }
        },"myThread");
        t.start();
        while(true){
            try {
                Thread.sleep(1000);
                System.out.println(t.isAlive());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

run()方法执行完了打印helloworld之后线程就结束了,即PCB没有了, 但是t对象还在,此时再去调isAlive(),结果就是false.

当引用不指向对象,t才会被GC回收

如果让run()方法执行慢一点,就能看到true了

将run()方法改为

public void run() {
      for (int i = 0; i < 3; i++) {
         System.out.println("hello world!!");
         try {
         Thread.sleep(1000);
         } catch (InterruptedException e) {
         throw new RuntimeException(e);
         }
       }
}

运行后run()3s后才被销毁,期间isAlive()返回true,3s后线程结束,isAlive()返回false

 线程之间是并发执行并且是抢占式调度的,因此先执行哪个线程是不确定的,这里根据结果我们大概可以看到,第一轮,主线程先sleep,先执行t线程,然后打印了helloworld!!,紧接着也进入了sleep,接下来就是看谁先唤醒,然后继续执行,,从结果看到执行的是hello world!!因此还是t线程先唤醒,继续执行,第一轮执行结束,主线程打印true.进入sleep,第二轮开始,t线程打印helloworld!!,然后主线程打印true,进入sleep,然后时间来到了3s,t线程结束,主线程一直打印false

这两轮操作除了第一个helloworld是确定的,后面的hello在前还是true在前都是无法确定的,完全看调度器是如何调度的结果,这就是抢占式执行

看一个清楚点的例子:

public class ThreadDemo7 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            System.out.println("hello world!!");
        });
                t.start();
        System.out.println("hello main!!");
    }
}

这两个线成所执行的顺序完全就是随机的,也就是先打印出哪个,完全是不确定的 ,这和我们以前写代码,是固定的顺序执行的是不同的,理解多线程代码需要考虑到无数的顺序

总结一下

当run()没跑的时候,isAlive()返回false 

当run()正在跑的时候,isAlive()返回true

当run()跑结束的时候,isAlive()返回false 

3.终止线程的方法

中断一个线程不是让线程立即就停止工作,只是告诉它应该停止了,是否真的停止,要看线程内的代码逻辑

常见的中断线程有以下两种方式:1. 通过共享的标记来进行沟通2. 调用 interrupt() 方法来通知

3.1使用共享标志位通知中断线程

在主线程创建一个共享标志位flag,通过它的改变来通知线程是否中断

public class ThreadDemo8 {
    private static boolean flag = true;
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            while (flag){
                System.out.println("hrllo world!!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        flag = false;
    }
}

 运行结果

主线程sleep3s,因此t线程运行3s之后,共享标志位发生改变,t线程就结束了

注意:这个代码之所以能修改了标志位,就起到中断t的作用,完全取决于线程t的代码是什么逻辑,如果代码内部不用flag控制循环,那么标志位的改变也不起任何作用,因此,这个标志位的改变咱们就是说只是通知它要中断了,是否中断还是看代码内部来决定的

自定义的共享标志位这种方式,也是不能及时响应的,像循环里有sleep的代码,无法在更改标志位后立即响应,这时线程t已经执行了很多代码了,才会收到通知,下来我们看一下使用Thread自带的标志位通知

3.2使用Thread自带的标志位通知

public class ThreadDemo9 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
           while (!Thread.currentThread().isInterrupted()){
               System.out.println("hello world!!");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
           }
        });
        t.start();
        Thread.sleep(3000);
        t.interrupt();
    }
}
Thread.currentThread()

是Thread类的静态方法,通过这个方法可以获取到当前线程的对象的引用,谁调用它就会获取谁的对象的引用,类似于this

isInterrupted()

为true表示被终止,为false表示继续执行

!Thread.currentThread().isInterrupted()

如果在t.run()中被调用,获取的就是t线程

加了!是逻辑取反,当isInterrupted()是true时,是要中断线程的,while(flag)中flag取false才能中断,因此要加!来取反

t.interrupt()

表示终止线程,哪个对象调用就终止呢个线程,这里main线程调用t.interrupt()表示的是main线程通知t线程你该终止了!!

isInterrupted()相当于设置一个布尔变量,t.interrupt()方法是在设置这个变量.3.1中的方法是直接操作一个布尔变量,3.2的方法是把布尔变量操作封装到Thread方法中了

封装到Thread类之后,如果线程在sleep中休眠,此时调用interrupt()来唤醒t线程,这时就不继续休眠了.interrupt()会直接触发sleep中的异常

InterruptedException

导致sleep提前返回了,我们看一下上面代码的运行结果

 可以发现:前三次是正常执行的,然后调用t.interrupt()触发异常后t线程中断了,中断之后t线程又继续运行了!!这是什么原因呢?

是因为t.interrupt()后首先把线程内部的标志位设置成true,若线程再进行sleep,会唤醒sleep,触发异常!!但是还没完,触发异常之后,又将标志位在设置回false,相当于清空了标志位,导致了sleep的异常被catch了之后,代码继续执行!!因此我们看见的结果是先运行然后中断,然后继续运行!还要注意调用t.interrupt()只是main线程通知t线程终止,t线程并不是一定会终止!!

 这种情况是线程t忽略了main的终止请求

 

加上break后,线程t就立即响应main的终止请求 

 

这种情况是稍后进行终止

 在catch处可以添加任意代码,因此为什么sleep的标志位会被清除就很明了了,在sleep被唤醒之后,线程到底是要终止还是继续运行,选择权就交给程序员了!!可以通过代码控制到底继续执行还是终止

4.等待线程 join

线程是一个随机调度的过程,等待线程就是控制两个线程的结束顺序,因为线程调度是随机的,我们无法控制线程的开始顺序,但是能通过方法控制线程的结束顺序

使用的是join()方法

public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("hello world!!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        System.out.println("join前");
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join后");
    }
}

此处的join()方法作用就是让main线程等待t线程执行结束

当start启动t线程时,主线程和t线程就开始运行了,主线程走到t.join()时,就发生阻塞了!!

一直阻塞到t线程执行结束,主线程才会从阻塞中恢复过来,才能继续往下执行!!因此t线程一定是比主线程先结束的,就达到了有序结束线程的目的!

从结果也可以看出来,两个线程开始运行后,主线程先打印了join之前,然后t线程执行,此时主线程阻塞了,t线程执行的时候并没有继续执行,也就是打印join之后,当t执行完了,才打印的join之后

还有一个问题,如果主线程执行join之前,t线程就结束了,会发生什么?

调整一下代码,让主线程sleep5s,其它地方不变,t线程3s就结束了,我们看效果 

 结果:t线程执行结束后,主线程是没有阻塞的,直接返回了,执行结束了 

因此假设开始执行join时,t已经结束了,join就不会再阻塞了,而是会立即返回!!

 join方法有下面三种:

方法

说明

public void join()一直等待,等到线程结束
public void join(long mills)等待线程结束,最多等 millis 毫秒
public void join(long mills,int nanos)等待线程结束,最多等 millis 毫秒,但可以更高精度

第二种比较常用,如果等到一定的时间没有结果,就不等了,一直死等会让程序无法继续执行了!

5.获取当前线程的引用

这个方法之前就已经了解过了

public static Thread currentThread();

功能:返回当前线程对象的引用

这是一个静态方法,可以直接通过类名调用,不需要实例化对象来调用

public class ThreadDemo11 {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
    }
}

 结果是获取当前线程的对象的引用

该方法是通过类名调用的,也就是类方法,为什么不构造一个新的关键字表示"类属性类方法"?

当构造一个新的关键字,必然要有一个名字,这个名字肯定不能作为变量名,方法名,一旦引入新的关键字,就需要考虑改动所有和它冲突的方法名,变量名,那么带来的结果是很严重的,因此就直接把static关键字拿过来使用了,不管他本来什么意思,直接赋予了新的使命! 

6.休眠当前线程

本质上是让这个线程不参与调度,不去cpu上执行了

线程调度是不可控的,因此休眠时间会大于等于参数设置的时间,即使你参数设置的时间到了,也不一定会立即调度然后执行这个线程

之前谈到过就绪队列,链表中的PCB都是等待调度的就绪状态,如果A线程在就绪队列中,并且调用sleep,那么A就会立即进入一个阻塞队列,这个队列的PCB都是阻塞的,不参与调度.

当这个PCBsleep结束之后回到就绪队列,考虑到实际的调度开销,对应的线程回到就绪队列后是无法立即被调度的!!!

看一下休眠的方法

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis毫秒
public static void sleep(long millis, int nanos) throwsInterruptedException高精度的休眠
 public static void main(String[] args) {
        System.out.println(System.currentTimeMillis());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis());
    }

 结果是main线程休眠了3s然后继续执行!

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

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

相关文章

Java安全--篇2-类的动态加载

类的动态加载 首先我们来了解一下构造代码块和静态代码块&#xff1a;Java中静态代码块、构造代码块、构造函数、普通代码块 - YSOcean - 博客园 // 静态代码块 static {System.out.println("静态代码块"); }// 构造代码块 {System.out.println("构造代码块&q…

使用Jetpack组件Navigation实现Android开发中页面跳转

使用Jetpack组件Navigation实现Android开发中页面跳转 ​目录 一、前言 1.概述 2.导航图的创建&#xff08;官网&#xff09; 二、基本使用 1.依赖配置 2.具体实例&#xff1a;使用Navigation实现页面的跳转。 2.1.class的创建 2.2 、页面布局文件的创建 2.3 向 Acti…

Abaqus血管支架仿真攻略之几何创建与网格划分

作者&#xff1a;江丙云&#xff0c;仿真秀平台优秀讲师 前不久&#xff0c;笔者推送的冠脉支架的参数化建模和优化、Abaqus网格卷曲WrapMesh&#xff0c;冠脉支架的参数化建模和优化&#xff0c;以及Abaqus疲劳分析|Goodman插件等原创文章后&#xff0c;后台留言的读者众多&a…

GDP-海藻糖,5‘-鸟苷二磷酸岩藻糖,GDP-fucose ,CAS:15839-70-0

产品名称&#xff1a;GDP-海藻糖&#xff0c;5-鸟苷二磷酸岩藻糖&#xff0c;二磷酸鸟苷岩藻糖&#xff0c;GDP-L-岩藻糖 英文名称&#xff1a;GDP-fucose&#xff0c;Guanosine 5-diphosphate-L-fucose disodium salt CAS&#xff1a;15839-70-0 Mol. Formula C16H23N5O…

基于模糊神经网络算法预测电价(Matlab代码实现)

&#x1f4cb;&#x1f4cb;&#x1f4cb;本文目录如下&#xff1a;⛳️⛳️⛳️ ​ 目录 1 概述 2 模糊神经网络简介 3 运行结果 4 参考文献 5 Matlab代码实现 1 概述 近年来,随着能源短缺和环境问题的日益凸显,太阳能、风能等各种形式的清洁能源得到广泛应用,微网作为分布式…

【云原生 | 46】高可用的开源键值数据库Etcd的安装与使用

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

第二证券|超300家机构关注两大赛道龙头,透露市场增长及发展方向

中科创达、奥普特成为本周调研组织数量最多的两家公司。 智能操作体系龙头获365家组织调研 证券时报数据宝计算&#xff0c;11月27日至12月3日&#xff0c;组织算计调研上市公司291家。被调研方多属于电子、机械设备、医药生物、电力设备、计算机、国防军工等板块&#xff0c;…

安卓属性动画

​ 一&#xff0e;三种安卓动画 Tween Animation(补间动画、视图动画)&#xff1a;通过对场景里的对象不断做图像变换&#xff08;平移、缩放、旋转&#xff09;产生的动画效果&#xff0c;即是一种渐变动画。 Frame Animation(帧动画)&#xff1a;顺序播放事先做好的图像&…

基于PLC的工业晾晒架系统

目录 前言 6 第一章 工业晾晒架的发展现状及趋势 7 1.1自动工业晾晒架的基本介绍 7 1.2自动工业晾晒架发展史和发展现状 8 第二章 自动晾晒架的智能模块 9 2.1自动晾晒架的结构框图 9 2.2自动晾晒架的机械理论 10 第三章 自动晾晒架的硬件设计 11 3.1电源设计部分 12 3.2 PLC的…

组合模式

文章目录思考组合模式1.组合模式的本质2.何时选用组合模式3.优缺点4.实现思考组合模式 组合模式实际上就是让客户端不再区分操作的是组合对象还是叶子对象&#xff0c;而是以一个统一的方式来操作。 1.组合模式的本质 组合模式的本质:统一叶子对象和组合对象。 组合模式通过把叶…

No.179 念念随风上九霄

引言有人跟老梁说&#xff0c;你挺忙的吧&#xff0c;更新变少了。害&#xff0c;可不是嘛&#xff1f;时间不太够&#xff0c;凑不出来了。凑不出来就不凑它了&#xff0c;扯扯其他的吧。在大城市生活节奏是快&#xff0c;个人也被裹挟着运转&#xff0c;无处可逃。从早到晚&a…

[附源码]计算机毕业设计基于SpringBoot动漫电影网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

如何用 7 分钟击破 Serverless 落地难点?

当前&#xff0c;Serverless 覆盖的技术场景正在不断变广。Serverless 已在微服务、在线应用、事件驱动、任务处理等众多场景被验证且广泛应用 。当你想要部署一个网站时&#xff0c;需要自己购买服务器并花费时间去维护&#xff0c;造成资源浪费不说&#xff0c;还要耗费精力。…

【NR 物理资源】

NR中与物理资源相关的概念主要包括天线端口、资源网格、资源单元、资源块RB和BWP等。 文章目录天线端口&#xff08;Antenna Ports&#xff09;资源网格Resource grid和资源单元RE资源块Resource Block部分带宽BWP天线端口&#xff08;Antenna Ports&#xff09; 天线端口定义 …

qmake source code 解读

qmake的主要功能执行入口在main.cpp中的runQMake(int argc, char **argv)中。其主要框架如下: runQMake(int argc, char **argv){QMakeVfs vfs; //初始化qmake的文件系统。virtual file system。vfs会为每个文件赋予一个id,并提供根据id进行操作的函数。Option::vfs &v…

交通流的微观模型(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

用好单例设计模式,代码性能提升300%

目录 一次请求执行流程java代码是如何运行的&#xff1f;堆内存满了后怎么办&#xff1f;用单例模式如何优化系统性能&#xff1f; 大家好&#xff0c;今天给大家分享一个写代码的设计模式&#xff0c;就是我们最最耳熟能详的单例设计模式。 可能很多人都听说过这个单例设计模…

基于Dijkstra和A*算法的机器人路径规划(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 网络分析是GIS中非常重要的空间分析功能之一, 最短路径分析又是网络分析的核心算法, 该算法的效率决定了网络分析的功能和效率…

【CSDN】官方Markdown示例教程

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…

Docker学习系列3:常用命令之容器命令

本文是Docker学习系列教程中的第三篇。前几篇教程如下&#xff1a; 「图文教程」Windows11下安装Docker Desktop 「填坑」在windows系统下安装Docker Desktop后迁移镜像位置 Docker学习系列1-如何安装docker? 【Docker学习系列】Docker学习2-docker设置阿里云镜像加速器 【Doc…