【Java】多线程Thread类

1. 进程与线程

进程与线程的基本认识

进程(Process):进程是程序的一次动态执行过程,它经历了从代码加载、执行、到执行完毕的一个完整过程;同时也是并发执行的程序在执行过程中分配和管理资源的基本单位,竞争计算机系统资源的基本单位。

线程(Thread):线程可以理解为进程中的执行的一段程序片段,是进程的一个执行单元,是进程内可调度实体,是比进程更小的独立运行的基本单位,线程也被称为轻量级进程。

即使多进程可以提高硬件资源的利用率,但是进程的启动和销毁需要消耗大量的系统性能,从而导致程序的执行性能下降。所以为了进一步提升并发操作的处理能力,在进程的基础上又划分了多线程概念。

2. 多线程实现

Thread类实现多线程

 Thread类的方法

1.通过继承Thread类,并重写父类的run()方法实现
public void run(){ }

定义线程类:


class MyThread extends Thread{@Overridepublic void run() {while(true){System.out.println("hello Thread");try{Thread.sleep(1000);}catch(InterruptedException e){throw new RuntimeException(e);}}}
}
public class Demo1 {public static void main(String[] args)throws InterruptedException {Thread t=new MyThread();t.start();//创建一个线程//t.run();while(true){System.out.println("hello main");Thread.sleep(1000);}//两个循环在同时进行}
}

Runnable接口实现多线程

使用Thread类的确可以实现多线程,但是也容易发现它的缺陷:面向对象的单继承局限,因此才采用Runnable接口来实现多线程。

该接口的定义如下(以下并不需要在代码中实现):


class MyRunnable implements Runnable{@Overridepublic void run(){while(true){System.out.println("hello main");try{Thread.sleep(1000);}catch(InterruptedException e){throw new RuntimeException(e);}}}
}
public class Demo2 {public static void main(String[] args)throws Exception{Runnable runnable=new MyRunnable();Thread t=new Thread(runnable);t.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

Thread(String name)后边两种方法,我们可以给线程对象命名。

默认情况下,线程对象名字是Thread-N,N是从0开始增加。

3.Thread常见方法

start()

start() 启动一个线程。

start()方法可以开启一个线程,线程创建好后是不会开始执行的,要使用start来开启。

只有当start(),操作系统内核才会创建一个真真正正的线程PCB,然后去调用run()方法,此时操作系统层面才会真的创建一个线程。

sleep()

使用sleep时会有一个中断异常(非受查异常),需要我们手动抛出

join()

join(): 等待一个线程;

join(t)表示等待一个线程t毫秒。
因为我们线程是随即调度的过程,线程的执行顺便我们无法把控,但在一些场景下我们需要有明确的线程程序顺序,等待线程,就是可以控制两个线程的结束顺序。

比如在main方法中有两个线程t1、t2,在主线程中有t1.join() ,那么主线程就要阻塞 等待t1线程执行完了才能在执行。如果在t1线程中有t2.join(),那么t1线程就要阻塞 等待t2线程执行完了才能执行任务。

如果去掉join()方法后,主线程与Thread线程抢占式执行!


public class Demo12 {public static void main(String[] args)throws Exception {Thread t=new Thread(()->{for(int i=0;i<3000;i++){System.out.println("hello thread");try{Thread.sleep(1000);}catch(InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程结束");});t.start();t.join(3000);//等待线程t执行完毕System.out.println("main 线程结束");}
}

中断线程

线程中断: 我们这里的中断,并不是线程立即就结束了,而是通知该线程,你应该结束了,但实际是否结束,取决于线程里具体的代码

package Thread;public class Demo3 {public static  boolean flag=true;public static void main(String[] args)throws InterruptedException{Thread t1=new Thread(()->{while(flag){System.out.println("hello Thread");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}});t1.start();Thread.sleep(3000);flag=false;}
}

flag 变量的作用是作为线程执行的控制开关,用于安全地终止 t1 线程的循环执行。

flag 变量是主线程与 t1 线程之间的一个通信媒介,通过修改它的值,主线程可以安全地通知 t1 线程“该停止工作了”,避免了线程的无限循环。如果没有 flagt1 线程的 while(true) 循环将无法终止,导致线程永久运行

即使 t1 线程因 sleep 进入阻塞状态,只要 sleep 时间结束,线程恢复运行后会立即检查 flag,从而响应终止信号。

4.Thread类的常见属性

getId():

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

package Thread;class MyThread1 extends Thread{@Overridepublic void run(){System.out.println("hello word");}
}
public class getIdtest {public static void main(String[] args) {Thread t=new MyThread1();System.out.println(t.getId());}
}

getName: 

名称是我们构造方法设置的名称,如果没有设置,那就是默认名。

public class getNametest {public static void main(String[] args) {Thread t=new Thread();System.out.println(t.getName());//因为我们没有命名,所以使用的是默认名。}
}

getState(): 

状态:

getState()方法可以获取当前Thread对象的状态,这是Java层面定义的线程状态,要注意和PCB上的区分。

线程有6种状态:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING,  TERMINATED。

NEW表示创建好了一个Java线程对象,安排好了任务,只是还没有启动,没有调用start方法之前是不会创建PCB的,和PCB没有关系。

RUNNABLE是运行状态或就绪状态,在操作系统层面已经有了对应的PCB。

BLOCKED是阻塞状态的一种,在等待锁

WAITING表示一直没有时间限制的等待,一直等直到被唤醒。

TIMED_WAITING指定了等待时间的阻塞状态,过时就继续执行任务。

TERMINATED是执行结束,PCB已经销毁,Java层面的线程对象还在。

查看Thread对象的所有状态:

package Thread;public class Demo14 {public static void main(String[] args) {for(Thread.State state: Thread.State.values()){System.out.println(state);}}
}

getPriority: 

可以获取当前线程的优先级,但没有太大的用,实际还得取决于操作系统内核的具体调度。

package Thread;public class test {public static void main(String[] args) {Thread t=new Thread();System.out.println(t.getPriority());}
}

isDaemon(): 

是否为守护线程(也叫后台线程), 简单的理解一下,我们手动创建的线程都是前台线程,JVM自带的线程都是后台线程,我们也可以通过setDaemon()方法将前台线程设置为后台线程。

 public static void main(String[] args) {Thread t=new MyThread2();System.out.println(t.isDaemon());}

isAlive(): 

线程的run方法是否执行结束。

package Thread;
class MyThread2 extends Thread{@Overridepublic void run(){System.out.println("hello thread1");}
}
public class Demo4 {public static void main(String[] args) {Thread t=new MyThread2();System.out.println(t.isAlive());t.start();System.out.println(t.isAlive());}}

interrupt()方法

第一种解释:

  1. 发送信号:通知线程“需要中断当前操作”,而非强制杀死线程。
  2. 打破阻塞:中断 sleep/wait 等阻塞方法,让线程从阻塞中唤醒并处理中断。
  3. 协作终止:线程通过检查中断状态(isInterrupted())或处理 InterruptedException,决定是否结束,体现“谁运行谁控制”的设计原则

在 Demo3 中,正是由于 t1 线程内部通过 while (!isInterrupted()) 主动响应中断信号,主线程的 t1.interrupt() 才能安全、优雅地终止线程。

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

第二个解释:

1.把线程内部的标志位设置为true
2.如果线程正在sleep,会触发异常,将sleep唤醒。
sleep唤醒的同时,会清空标志位,将刚才设置的标志位在设置为false(这就导致,我们的循环会继续执行).
如果我们想去中断,我们可以在异常里加一个break。

2.3 多线程运行状态

任意线程具有5种基本的状态:

1.创建状态

实现Runnable接口和继承Thread类创建一个线程对象后,该线程对象处于创建状态,此时它已经有了内存空间和其它资源,但他还是处于不可运行的。

2.就绪状态

新建线程对象后,调用该线程的start方法启动该线程。启动后,进入线程队列排队,由CPU调度服务。

3.运行状态

就绪状态的线程获得处理器的资源时,线程就进入了运行状态,此时将自动调用run方法。

4.阻塞状态

正在运行的线程在某些特殊情况下,如:当前线程调用sleep、suspend、wait等方法时,运行在当前线程里的其它线程调用join方法时,以及等待用户输入的时候。只有当引起阻塞原因消失后,线程才能进入就绪状态。

5.终止状态

当线程run方法运行结束后,或者主线程的main()方法结束后,线程才能处于终止状态,线程一旦死亡就不能复生。

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

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

相关文章

C/C++复习(四)

一.模版 模版涉及的是泛型编程&#xff0c;即通过编译器去确定类型的编程方式&#xff0c;模版分为&#xff1a;类模板和函数模版&#xff0c;下面我们一一复习&#xff1a; 函数模版&#xff1a; 格式&#xff1a; template<typename T1, typename T2,......,typename Tn&g…

022 基础 IO —— 文件

&#x1f984; 个人主页: 小米里的大麦-CSDN博客 &#x1f38f; 所属专栏: Linux_小米里的大麦的博客-CSDN博客 &#x1f381; GitHub主页: 小米里的大麦的 GitHub ⚙️ 操作环境: Visual Studio 2022 文章目录基础 IO —— C 语言文件 I/O 操作基础前言1. C 语言文件操作函数汇…

MNN LLM Chat iOS 流式输出优化实践

本文介绍了在 iOS 平台上使用 MNN 框架部署大语言模型&#xff08;LLM&#xff09;时&#xff0c;针对聊天应用中文字流式输出卡顿问题的优化实践。通过分析模型输出与 UI 更新不匹配、频繁刷新导致性能瓶颈以及缺乏视觉动画等问题&#xff0c;作者提出了一套包含智能流缓冲、U…

【开发技巧】VS2022+QT5+OpenCV4.10开发环境搭建QT Creator

VS2022编译器支持配置 QT5默认安装以后支持的是VS2015与VS2017&#xff0c;不支持VS2022&#xff0c;所以必须首先在Qt Creator中配置支持VS2022。配置顺序如下&#xff1a; 首先打开【工具】->【选项】 然点击Kits里面的【编译器】选项。点击Manual下面的【C】然后点击【…

【Linux系统】动静态库的制作

前言&#xff1a; 上文我们讲到了文件系统【Linux系统】详解Ext2&#xff0c;文件系统-CSDN博客 本文我们来讲讲动静态库的制作 库 【Linux】编译器gcc/g及其库的详细介绍_linux gcc 有哪些库-CSDN博客 这篇文章的第4大点&#xff0c;简单是介绍了一下库的基本概念。 静态库 静…

链式二叉树的基本操作——遍历

本文笔者将带领读者一起学习链式二叉树的一些基本语法&#xff0c;至于更难一些的插入删除等&#xff0c;笔者将在后续C更新后再次详细带领大家学习。 首先&#xff0c;在进行二叉树之前&#xff0c;我们需要一颗二叉树&#xff0c;而二叉树的初始化现阶段实现不太现实&#x…

Windows运维之以一种访问权限不允许的方式做了一个访问套接字的尝试

一、问题场景 在Windows 上运维服务过程中&#xff0c;经常会遇到运行服务&#xff0c;部署安装时候无任何问题&#xff0c;后续再某个特殊时间点&#xff0c;突然服务无法启动了。再次启动时&#xff0c;提示端口占用与以一种访问权限不允许的方式做了一个访问套接字的尝试。 …

2020/12 JLPT听力原文 问题二 3番

3番&#xff1a;レストランで、女の人と店長が話しています。店長はサラダについて、どんなアドバイスをしていますか。女&#xff1a;店長、この前話してた新しいランチメニューのサラダを作ってみたんですが、どうでしょうか。 男&#xff1a;ああ、サラダだけで満足できるっ…

芯片行业主要厂商

作为一个小白&#xff0c;每次淘宝买芯片时看到相似的命名规则&#xff1a;“OPA、AD、LT、MAX”等等时&#xff0c;我不禁好奇这些芯片行业大厂有哪些&#xff0c;所以查了些资料&#xff1a; 1. 德州仪器&#xff08;Texas Instruments, TI&#xff09; 公司概况&#xff1…

【BLE系列-第四篇】从零剖析L2CAP:信道、Credit流控、指令详解

目录 引言 一、L2CAP主要功能 二、L2CAP帧格式及信道概念 2.1 逻辑链路是什么&#xff1f; 2.2 逻辑信道的作用 2.3 L2CAP帧格式介绍 三、L2CAP信令信道 3.1 信令信道帧格式说明 3.2 信令信道指令介绍 3.2.1 信令信道指令一览表 3.2.2 Credit流控规则 引言 在BLE协…

CSS保持元素宽高比,固定元素宽高比

方法一&#xff1a; <div class"hcp-fixed-aspect-ratio-box">这里是正文内容 </div>.hcp-fixed-aspect-ratio-box {width: 50%;color: #FFFFFF;margin: 100px auto;background: #FF0000;/* 宽高比2:1&#xff0c;兼容性可能不太好 */aspect-ratio: 2 / …

数据分析小白训练营:基于python编程语言的Numpy库介绍(第三方库)(上篇)

&#xff08;一&#xff09;Numpy库的安装安装指定版本的Numpy库&#xff0c;打开命令提示符&#xff0c;输入下图内容&#xff0c;只需要将1.25.5的版本修改成个人需要的版本&#xff0c;然后按下回车键&#xff0c;numpy库就安装在python中&#xff1a;指定版本numpy库安装可…

从 Windows 到 Linux 服务器的全自动部署教程(免密登录 + 压缩 + 上传 + 启动)

一、准备工作 1. 环境说明 本地开发环境&#xff1a;Windows 服务器&#xff08;需执行部署脚本&#xff09;目标服务器&#xff1a;Linux 服务器&#xff08;需安装 node.js、pm2、unzip&#xff09;核心工具&#xff1a;7-Zip&#xff08;压缩&#xff09;、OpenSSH&#x…

智能汽车领域研发,复用云原始开发范式?

汽车电子电气架构演进趋势&#xff1a;分散的功能ECU -> 域控制器 -> 中央计算服务器汽车电子方案与架构在发展与迭代时会使用虚拟化方法几种可行的软硬一体化方案&#xff1a;多ECU&#xff0c;硬件隔离&#xff0c;硬件分区&#xff0c;车规级多核硬件架构 Hypervisor…

数据电台询价的询价要求

技术规格及主要参数 1.电台基本要求&#xff1a; 1.1 电台中的信号处理基于FPGA设计&#xff0c;采用FPGAARM高速AD/DA设计架构&#xff1b; 1.2 具备频谱感知、自主选频、跳频、扩频等功能&#xff1b; 1.3 具备链路质量信息、自组网路由信息、电池电压监测信息、北斗定位信息…

IoT/HCIP实验-5/基于WIFI的智慧农业实验(LwM2M/CoAP+PSK+ESP8266 连接到 IoTDA)

文章目录概述WIFI8266 通信模组WIFI模组也用AT指令&#xff1f;ESP8266 内置协议栈?支持的无线网络模式MCU通过串口与模组交互Wifi模组做客户端PC-AT接入路由器向本地TCP服务发数据用代码接入你家路由器已接入AP&#xff08;你家Wifi&#xff09;平台侧开发工程配置和编译工程…

定时器输出PWM波配置(呼吸灯)

使用定时器 4 通道 3 生成 PWM 波控制 LED1 &#xff0c;实现呼吸灯效果。 频率&#xff1a;2kHz&#xff0c;PSC71&#xff0c;ARR499pwm.c:#include "pwm.h" // 本模块头文件&#xff1a;应声明 pwm_init/pwm_compare_set 等原型、并包含 HAL 头//&#xff08;示…

[ai-agent]环境简介之沙盒e2b vs daytona

所谓的环境的就是agent运行在哪里&#xff0c;或者是agent和那里进行交互。 最常见的环境就是本地开发环境&#xff0c;也就是个人主机&#xff0c;但是存在问题就是没有办法出网和横向扩展。 在沙盒之前也是有其他选择的&#xff1a; 云服务器&#xff0c; 虚拟机&#xff0c;…

【前端面试题】前端面试知识点(第三十一题到第六十一题)

三十一. CSS实现垂直水平居中 实现元素的垂直水平居中是前端开发中的常见需求,主要有以下几种思路: text-align + line-height实现单行文本水平垂直居中 适用于单行文本元素,通过text-align: center实现水平居中,line-height等于容器高度实现垂直居中 text-align + vertic…

嵌入式练习项目——————抓包获取天气信息

一、内容 尝试通过实时天气接口 - 数据接口 - NowAPI此网站获取天气信息&#xff0c;实现可以发送城市查询当前天气和未来天气 二、获取请求报文 可以根据测试示例看到获取内容&#xff0c;此时数据是cJSON格式&#xff0c;我们首先要通过合适的网址抓包获取到请求报文&#x…