Thread类的属性及常见方法

server/2024/9/24 12:59:13/

Thread是JVM用于管理线程的类,换句话说,每个线程都有一个Thread对象与之关联,一个Thread对象有ID、名称、优先级、状态等属性,JVM会将这些Thread对象组织起来,用于线程调度,线程管理。

1. Thread的常见构造方法

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

给Thread命名的意义:上一篇文章中我们使用jconsole查看过自定义的线程,由于没有命名,它的默认名称为Thread-0,我们可以在构造函数中给线程命名(与内核中的线程一一对应),以便后续调试。

java">public class Demo7 {public static void main(String[] args) {Thread thread = new Thread(()->{while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}, "myThread");thread.start();while (true) {System.out.println("hello world");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

打开jconsole再次查看:

image.png

2. Thread的常见属性

属性获取方法
ID:线程在JVM中的唯一标识符getId()
名称getName()
状态getState()
优先级getPriority()
是否为守护线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

守护线程的解释:创建出来的线程默认为非守护线程,守护线程不会阻止进程结束,非守护线程会阻止进程结束。也就是说所有非守护线程必须执行完了进程才会结束,如果想设置线程为守护线程可以使用setDaemon(true)方法来设置线程为守护线程。

使用一下上面的api,查看Thread的属性:

java">public class Demo8 {public static void main(String[] args) {Thread t = new Thread(() -> {while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}, "myThread");t.start();System.out.println(t.getId());System.out.println(t.getName());System.out.println(t.getState());System.out.println(t.getPriority());System.out.println(t.isDaemon());System.out.println(t.isAlive());System.out.println(t.isInterrupted());}
}

运行结果:下面都是线程一瞬间的属性

11
myThread
TIMED_WAITING
5
false
true
false

3. 启动一个线程——start()

创建出Thread实例,只是在JVM的堆区中创建出了一个Thread对象,并没有在操作系统中创建出一个线程,调用了start()方法才是在操作系统中创建出一个线程并完成指定的入口方法(重写的run()方法或者Runnable对象),并且当线程的入口方法完成后,该线程就随之结束了。

4. 获取线程引用——currentThread()

Thread类有一个静态方法currentThread(),用于在入口方法(线程需要做的事)内部获取到线程的引用。

  • 如果是继承Thread类,重写run方法,可以直接在run方法内使用this获取到线程引用
  • 但如果是Runnable内重写run方法,this就不管用了,需要使用Thread.currentThread()方法获取引用

5. 中断线程——interrupt()

所谓的中断线程,就是让线程尽快把入口方法执行结束,Java中把中断的决定权交给被中断的线程本身,接下来我将以两种方式举例如何中断线程。

  1. 直接使用标识为来区分线程是否需要中断
java">public class Demo9 {private static boolean isQuit = false;public static void main(String[] args) {Thread thread = new Thread(() -> {while (!isQuit) {System.out.println("thread is running..");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("thread is finished! ");});thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}//主线程休眠五秒后将标志位设为trueisQuit = true;}
}
thread is running..
thread is running..
thread is running..
thread is running..
thread is running..
thread is finished! Process finished with exit code 0

这种方案是可行的,Thread其实内置了标志位,不需要我们手动创建标志位

  1. 使用Thread自带的标志位来判断是否要中断

设置标志位的方法如下:

java">//调用后标志位就设为true了
thread.interrupt();

判断标志位的方法如下:

java">//普通成员方法,中断后不清除中断标志(还是true)
Thread.currentThread().isInterrupted()
java">//静态成员方法,中断后清除中断标志(变为false)
Thread.interrupted()

使用这两个方法来中断线程:

java">public class Demo10 {public static void main(String[] args) {Thread thread = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("thread is running..");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}//主线程休眠五秒后中断线程System.out.println("控制线程退出");thread.interrupt();}
}

此时会发生一个问题,运行结果如下:

thread is running..
thread is running..
thread is running..
thread is running..
thread is running..
控制线程退出
Exception in thread "Thread-0" java.lang.RuntimeException: java.lang.InterruptedException: sleep interruptedat thread.Demo10.lambda$main$0(Demo10.java:18)at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at thread.Demo10.lambda$main$0(Demo10.java:16)... 1 more

thread.interrupt()在线程非阻塞状态和阻塞状态下会有两种行为:

  1. 非阻塞状态:thread.interrupt()会修改内置的标志位为true
  2. 阻塞状态:thread.interrupt()方法会使如sleep()这样阻塞线程的方法出现异常,又由于我们在catch代码块中捕获到异常的处理方式是直接throw抛出异常,因此进程就会因为异常而意外中断。

由于我们写的该线程大部分时间都是处于阻塞状态,因此我们需要对catch代码块中的代码进行特殊处理:

java">Thread thread = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("thread is running..");try {Thread.sleep(1000);} catch (InterruptedException e) {break;}}
});

此时就可以正常地中断线程了:

thread is running..
thread is running..
thread is running..
thread is running..
thread is running..
控制线程退出Process finished with exit code 0

6. 等待一个线程——join()

join()方法的行为:

  1. 如果被等待的线程还没执行完,就阻塞等待
  2. 如果等待的线程已经执行完,就直接返回

由于调度器的策略是我们无法干涉的,但是使用join()可以控制一些必要的执行顺序,这里我将举两个案例来帮助理解join()方法

上一篇文章中我们使用了下面的代码来控制main函数阻塞,等待t1和t2执行完了,main才能解除阻塞,继续往下执行:

java">public class Demo6 {private static final long COUNT = 10_0000_0000;private static void serial() {long begin = System.currentTimeMillis();int a = 0;for (int i = 0; i < COUNT; i++) {a++;}a = 0;for (int i = 0; i < COUNT; i++) {a++;}long end = System.currentTimeMillis();System.out.println("共花费了" + (end - begin) + "ms");}public static void main(String[] args) {concurrency();}private static void concurrency() {long begin = System.currentTimeMillis();Thread t1 = new Thread(() -> {for (int i = 0; i < COUNT; i++) {int a = 0;a++;}});Thread t2 = new Thread(() -> {for (int i = 0; i < COUNT; i++) {int a = 0;a++;}});t1.start();t2.start();try {//等待t1,t2线程结束才接触阻塞并执行后续代码t1.join();t2.join();} catch (InterruptedException e) {throw new RuntimeException(e);}long end = System.currentTimeMillis();System.out.println("共花费了" + (end - begin) + "ms");}
}

第二个场景:t1,t2,main并发运行,但是他们的结束顺序必须是t1、t2、main,此时我们同样可以使用join()控制线程结束的顺序:

java">public class Demo11 {public static void main(String[] args) throws InterruptedException {System.out.println("main begin");Thread t1 = new Thread(() -> {System.out.println("t1 begin");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t1 end");});t1.start();Thread t2 = new Thread(() -> {System.out.println("t2 begin");//等待t1结束try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t2 end");});t2.start();//等待t2结束t2.join();System.out.println("main end");}
}

上面那种写法是一直阻塞到线程结束,但是在实际开发中,更推荐使用最多阻塞多久就不阻塞了的方式(第2、3种方法):

image.png

7. 休眠线程——sleep()

sleep()方法已经在前面的演示代码中使用了很多遍了,这里我们具体谈谈操作系统中做了什么。

第一章我们在引入线程之前讲了进程的五种状态:运行态的进程在cpu上运行,就绪态的线程在就绪队列中等待调度,阻塞态的进程在阻塞队列中,不参与调度。

引入线程后调度的基本单位变成了线程,一个线程对应一个TCB,在就绪队列中的TCB参与调度器的随机调度,在阻塞队列中的TCB不参与调度器的随机调度。

  1. 在调用sleep()方法前,它们是这样的:

image.png

  1. 当调用到sleep()后,该线程立刻就从运行态变为了阻塞态,并且将TCB放入阻塞队列中,并且CPU立马从就绪队列中调度一个新的线程运行:

image.png

  1. 当sleep的时间结束时,会唤醒该线程,该线程才从阻塞态变为就绪态,并且被放入就绪队列中等待调度器随机调度:

image.png


http://www.ppmy.cn/server/39761.html

相关文章

RK3588 usb adb调试

问题&#xff1a;2路usb3.0 otg&#xff0c;在使用其中一路typeC1作用adb功能使用后&#xff0c;将这路设置成host模式后&#xff0c;另外一路typeC0设置device&#xff0c;这路还是无法当做usb adb来使用。 查看usb typeC1当前模式 cat /sys/kernel/debug/usb/fc400000.usb/m…

防爆气象仪

TH-WFB5矿山作为一个特殊的工作环境&#xff0c;其安全生产一直是重中之重。而矿山环境中的气象变化&#xff0c;如温度、湿度、风速、风向等&#xff0c;不仅直接影响矿山的日常生产活动&#xff0c;还关系到矿工的生命安全。因此&#xff0c;防爆气象仪的应用显得尤为重要。 …

【Pytorch】3.Transforms的运用

什么是Transforms 在PyTorch中&#xff0c;transforms是用于对数据进行预处理、增强和变换的操作集合。transforms通常用于数据载入和训练过程中&#xff0c;可以包括数据的归一化、裁剪、翻转、旋转、缩放等操作&#xff0c;以及将数据转换成PyTorch可以处理的Tensor格式。 Tr…

JVM进程缓存 Caffeine

JVM进程缓存 Caffeine 初识Caffeine Caffeine是一个基于Java8开发的&#xff0c;提供了近乎最佳命中率的高性能的本地缓存库。 ben-manes/caffeine: A high performance caching library for Java (github.com) 实例代码 Test void testBasicOps() {// 创建缓存对象Cache&…

跨境电商行业蓬勃发展,武汉星起航引领卖家孵化新潮流

近年来&#xff0c;我国跨境电商行业在政府的大力扶持下呈现出强劲的发展势头。随着国内制造业结构的加速调整与居民消费需求升级态势的持续凸显&#xff0c;跨境出口规模占比稳步提升&#xff0c;跨境进口规模同样不断扩大&#xff0c;行业市场规模持续增长。在这一背景下&…

MYSQL变量的定义与使用

一、标识符的命名规范 #1、不能以数字开头 #2、不能使用关键字 #3、只能使用_和$符号&#xff0c;不允许使用其他符号 二、定义MYSQL变量的方法 set userName"小可爱"; #读取变量 select userName as 名称; #读取时包含赋值操作 select userName:海绵宝宝 as 赋值…

全网最详细IOS系统APP上架教程(二)

上一篇讲解了IOS系统APP上架注册苹果开发者账号需要的材料、邓白氏编码的注册等&#xff0c;本文将继续讲解后续流程。 详细步骤 三、申请苹果开发者账号 在苹果手机上安装Apple Developer 打开Apple Developer&#xff0c;用之前注册好的Apple ID登录&#xff0c;输入姓名身…

设计模式——备忘录模式(Memento)

备忘录模式&#xff08;Memento Pattern&#xff09;&#xff0c;也称为快照模式或Token模式&#xff0c;是GoF&#xff08;Gang of Four&#xff0c;四位设计模式专家&#xff09;提出的23种设计模式之一&#xff0c;属于行为模式。该模式的主要目的是在不破坏封装性的前提下&…