多线程初阶——线程状态
创始人
2024-05-23 14:10:55
0

多线程初阶——线程状态

文章目录

  • 多线程初阶——线程状态
    • 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
觉得不错就留下你的三连吧

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...