多线程初阶——线程状态

article/2024/4/13 15:04:17

多线程初阶——线程状态

文章目录

  • 多线程初阶——线程状态
    • 1.Thread类及常见构造方法
    • 2.Thread常见的方法
    • 3.线程相关的重要操作
      • 3.1启动线程—start()
      • 3.2中断线程
      • 3.3 等待线程— join()
      • 3.4 获取线程引用
      • 3.5休眠线程—sleep()
    • 4.线程的状态

1.Thread类及常见构造方法

方法说明
Thread()默认无参构造方法
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建线程对象,并给线程起名字
Thread(Runnable target,String name)使用Runnable对象创建线程对象,并给线程起名字

给线程起名字

public class demo1 {public static void main(String[] args) {Thread t = new Thread(() -> {while(true){System.out.println("Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"线程一");t.start();while (true){System.out.println("main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

image-20230129200540985

2.Thread常见的方法

属性方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

说明

getId()

ID是线程唯一标识,不同线程不会重复

getName()

线程的名称

getState()

表示线程当前所处的一个情况

getPriority()

获得线程的优先级

isDaemon()

JVM会在一个进程的所有非后台线程结束后,才会结束运行,这里的后台,和我们常说的手机后台应用类似线程创建的时候,默认是一个前台线程,前台线程可以阻止进程的退出,后台线程不影响进程的退出

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

image-20230129214257735

由于线程是前台进程,需要等待运行结束,进程才结束。代码为死循环,所以将会一直执行。

利用setDaemom()方法将线程设置为后台进程,等主线程执行完,进程就结束了,注意:先设置后台进程,再启动线程

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

image-20230129215820274

3.线程相关的重要操作

3.1启动线程—start()

创建Thread对象、重写run方法,只是给线程安排了任务,并没有执行,而调用start方法,才是创建出了线程

3.2中断线程

**线程结束其实就是让线程的入口方法执行完 **

而中断线程,其实就是让线程停止下来,结束入口方法的执行

有2种方法可以中断线程

**方法一:直接用自定义的变量来作为标志位 **

需要给标志位上加volatile关键字

这里我们以李四在银行取钱为例

public class Demo8 {private static class MyRunnable implements Runnable {public volatile boolean isQuit = false;@Overridepublic void run() {while (!isQuit) {System.out.println(Thread.currentThread().getName()+ ": 别管我,我忙着转账呢!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+ ": 啊!险些误了大事");}}public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName()+ ": 让李四开始转账。");thread.start();Thread.sleep(5 * 1000);System.out.println(Thread.currentThread().getName()+ ": 老板来电话了,得赶紧通知李四对方是个骗子!");target.isQuit = true;}
}

image-20230203010328854

方法二:使用Thread自带的标志位

Thread.interrupted()或者Thread.currenThread().isInterrupted()

public class Demo9 {private static class MyRunnable implements Runnable {@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()) {System.out.println(Thread.currentThread().getName()+ ": 别管我,我忙着转账呢!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+ ": 啊!险些误了大事");}}public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName()+ ": 让李四开始转账。");thread.start();Thread.sleep(5 * 1000);System.out.println(Thread.currentThread().getName()+ ": 老板来电话了,得赶紧通知李四对方是个骗子!");thread.interrupt();}
}

运行结果

image-20230203204711356

这时抛出了InterruptedException异常

这是为什么呢?

由于线程的有效任务是打印一句话,这个操作耗时比较小,大部分时间线程都在sleep状态,正常来说,当线程在运行真正有效任务时去中断才是一个有效的中断,而在线程休眠的时候中断,其实是把休眠给中断了,而休眠本身没有到指定的时间,所以抛出了InterruptedException异常

当我们去掉线程中的休眠时,结果如下

image-20230203220249387

这时候线程才真正的中断了

3.3 等待线程— join()

我们知道线程之间的执行顺序是根据系统调度随机执行的,但有时我们需要等待一个线程执行完,再执行下一个线程,这时我们需要一个方法明确等待线程结束

public class Demo10 {public static void main(String[] args) throws InterruptedException {Runnable target = () -> {for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName() + ":正在工作!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + "结束了工作");};Thread thread1 = new Thread(target, "李四");Thread thread2 = new Thread(target, "王五");System.out.println("李四先工作");thread1.start();thread1.join();System.out.println("李四结束了工作,王五开始工作");thread2.start();thread2.join();System.out.println("王五结束了工作");}
}

image-20230203221145829

join()其他方法

public void join()等待线程结束(一直等,知道线程执行的任务结束)
public void join(long millis)等待线程结束,但等待millis毫秒
public void join(long millis, int nanos)同理

3.4 获取线程引用

private static Thread currentThread()

返回当前线程对象的引用

3.5休眠线程—sleep()

让线程休眠休眠一会

图解sleep()的具体使用

image-20230204002702109

4.线程的状态

在Java线程分为6种状态

1. NEW:创建好了一个Java的Thread对象,并安排好了任务,没有调用start()方法之前,和PCB没有关系

2. RUNNABLE:运行+就绪状态,在执行任务时的一个常态之一

3. TIMED_WAITING:指定了一个时间的阻塞队列,过时不候

4. WAITING :没有指定时间的等待,一直死等

5. BLOCK:等待锁的状态

6. TERMINATED :结束,完成状态,PCB已经被销毁了,但是Java对象还在

查看线程状态

public class Demo14 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});System.out.println("线程创建之前:"+thread.getState());thread.start();Thread.sleep(1000);System.out.println("启动线程,创建好PCB后:"+thread.getState());thread.join();System.out.println("线程执行完成后:"+thread.getState());}
}

image-20230204004138603

线程之间相互转换

image-20230204004728035
觉得不错就留下你的三连吧


http://www.ngui.cc/article/show-861254.html

相关文章

【Python教程】如何实用File文件

1、读写文件 open()将会返回一个file对象&#xff0c;基本语法&#xff1a; open(filename,mode)ilename:是一个包含了访问的文件名称的路径字符串 mode:决定了打开文件的模式&#xff1a;只读&#xff0c;写入&#xff0c;追加等&#xff0c;默认文件访问模式为只读 不同模…

【栈】单调栈详情介绍及其运用

单调栈单调栈的概述&#xff08;Overview&#xff09;何时使用单调栈模拟单调递增栈单调栈的运用&#xff08;算法练习题&#xff09;模板【练习一、单调栈】739. 每日温度【练习二、单调栈哈希表】496. 下一个更大元素 I【练习三、单调栈循环数组】503. 下一个更大元素 II【练…

Linux日志分析工具之AWStats

Linux日志分析工具之AWStats &#x1f4d2;博客主页&#xff1a; 微笑的段嘉许博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由微笑的段嘉许原创&#xff01; &#x1f4c6;CSDN首发时间&#xff1a;&#x1f334;2…

力扣sql简单篇练习(十)

力扣sql简单篇练习(十) 1 过去30天的用户活动 || 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 a 示例输入 b 示例输出 1.2 示例sql语句 # 多少天内使用Date_SUB函数,具体用法是Date_SUB(初始日期,interval 变更的天数 day) ,正数找过去负数找未来 # 变更天数多少…

Facebook 运营:如何制定内容策略

今天这篇文章的目的是帮助大家建立一个关于内容和营销策略的框架&#xff0c;以便在 Facebook上有效地执行它们。你可以用这个框架来创建内容、营销内容&#xff0c;以及营销传播的各种类型。这个框架中的每一个概念都应该在不同的主题下进行测试&#xff0c;并为你提供一个模板…

字体图标的实现原理

1.字体图标使用场景 主要用于显示网页中通用、常用的一些小图标。 精灵图是有诸多优点的&#xff0c;但是缺点很明显。 图片文件还是比较大的。图片本身放大和缩小会失真。一旦图片制作完毕想要更换非常复杂。 此时&#xff0c;有一种技术的出现很好的解决了以上问题&#xf…

11 |「哈希表」简析

前言 前言&#xff1a;刷「哈希表」高频面试题。 文章目录前言一、简介1、离散化1&#xff09;什么是离散化2&#xff09;离散化存储3&#xff09;离散化映射2、哈希表1&#xff09;什么是哈希表2&#xff09;哈希表存储3&#xff09;哈希函数4&#xff09;哈希冲突二、参考链接…

C++入门:运算符

运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符&#xff0c;并提供了以下类型的运算符&#xff1a;算术运算符关系运算符逻辑运算符位运算符赋值运算符杂项运算符& &#xff1a;只有2个都为1&#xff0c;那么结果是1&#xff0c;否则为0&…

密钥格式梳理

文章目录各种密钥格式简介DERPyCryptodome源码参考PEMOpenSSL命令操作参考资料各种密钥格式简介 两种编码方式&#xff1a; .der&#xff1a;用ASN.1语法编码的der格式&#xff1b; .pem&#xff1a;用BASE64编码的密钥&#xff1b; # ASN.1 ------&#xff08;序列化&…

【C++】对象与类

【C】对象与类 文章目录【C】对象与类1、定义1.1 对象的定义1.2 类的定义2、对象与类的创建2.1 类的创建2.2 对象的创建3、封装3.1 访问限定符3.2 对封装的解释4、类的实例化5、类、对象大小6、this指针6.1 this指针概念6.2 this指针特点1、定义 1.1 对象的定义 现实世界对对…