Java多线程编程,Thread类的基本用法讲解
文章目录
- 如何创建一个线程
- start 与 run
- 线程休眠
- 线程中断
- 线程等待
- 获取线程实例
如何创建一个线程
之前我们介绍了什么是进程与线程,那么我们如何使用代码去创建一个线程呢?线程操作是操作系统中的概念,操作系统内核实现了线程这样的机制,并且用户层提供了一些API供用户使用,Java标准库中Thread类可以视为是对操作系统提供的API进行了进一步的封装和抽象,所以我们创建的方式有很多我们可以;
继承Thread来创建一个线程类
class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("t1");}}
}public class Threadcreat {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();while (true){System.out.println("main");}}
}
实现Runnable接口
class MyRunnable implements Runnable {@Overridepublic void run() {while (true) {System.out.println("t1");}}
}public class ThreadCreat2 {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t1 = new Thread(myRunnable);t1.start();while (true) {System.out.println("main");}}
}
以上两种方法还可以使用内部类的方法实现:
public class ThreadCreat3 {public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {while (true) {System.out.println("t1");}}};thread.start();while (true) {System.out.println("main");}}
}
public class ThreadCreat3 {public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {while (true) {System.out.println("t1");}}});t1.start();while (true) {System.out.println("main");}}
}
但是我们实际的开发中最常用的创建线程的方式是使用lambda表达式的方式创建
public class ThreadCreat4 {public static void main(String[] args) {Thread t1 = new Thread(() -> {while (true) {System.out.println("t1");}});t1.start();while (true) {System.out.println("main");}}
}
多线程是用来提高程序的整体运行效率的,类似上面的几个代码如果我们没有使用多线程,那么将会在一个循环里面卡死,而多线程操作就可以同时跑两个死循环,统一时间可以干两件事。
start 与 run
有的同学还是会有一点疑问,上面代码中的start run等方法都是什么呢?
run方法表示了线程的入口方法是什么,里面的逻辑描述了此线程需要做哪些事,不需要程序员自己调用,系统会自动调用。
start方法表示真正从系统中创建一个新的线程,新的线程将会执行run方法。
线程休眠
public class ThreadCreat4 {public static void main(String[] args) {Thread t1 = new Thread(() -> {while (true) {System.out.println("t1");}});t1.start();while (true) {System.out.println("main");}}
}
此时我们觉得t1线程和主线程打印速度太快了,我们能否让我们的打印速度慢一点呢?可以,让线程睡一会觉不就可以了。
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (true) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1");}});t1.start();while (true) {Thread.sleep(1000);System.out.println("main");}}
}

sleep()方法就可以让线程休眠一会,方法的参数可以设置休眠的时间,此时主线程每个1s打印一次,t1线程每隔3s打印一次。
InterruptedException这个是多线程中常见的一个异常,如果在sleep()的线程被提前唤醒,可能会造成一些错误,所以当sleep()的线程被提前唤醒时会抛出一个InterruptedException。
线程中断
public class ThreadInterrupt {public static void main(String[] args) {Thread t1 = new Thread(() ->{while(true) {System.out.println("t1");}});t1.start();System.out.println("mian");}}
我们来看这个代码,因为线程t1中有一个死循环,此时会导致入口方法run无法执行结束,怎么办呢?我们需要设计一个标记。
public class ThreadInterrupt {public static boolean isQuit = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() ->{while(isQuit) {System.out.println("t1");}System.out.println("线程终止");});t1.start();System.out.println("mian");Thread.sleep(1000);isQuit = false;}
}

此时通过我们自己创建的结束标记位进行控制循环的结束,为了让我们更方便的实现上述功能,Thread类内置了一个标志位。
public class ThreadCreat4 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {try {System.out.println("t1");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();Thread.sleep(3000);t1.interrupt();}
}

我们使用标记位的目的是让循环结束,但是我们执行程序发现,循环并没有结束,这是为什么呢?使用interrupt()的作用其实有两个:
1、
Thread.currentThread().isInterrupted()这个方法可以获取到标记位的状态,标记位默认为false。
2、t1.interrupt();将标记位变为true,并且如果该线程在阻塞中,此时就会把阻塞状态唤醒,sleep()方法提前被唤醒就会抛出一个异常,sleep()被唤醒会自动的把isinterrupted标记位清空,所以导致下次循环继续执行。
如何解决这个问题呢?我们进行这样的修改:
public class ThreadCreat4 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {try {System.out.println("t1");Thread.sleep(1000);} catch (InterruptedException e) { break;}}});t1.start();Thread.sleep(3000);t1.interrupt();}
}
此时当t1.interrupt()将标志位变为true,并且提前将sleep()唤醒,此时我们直接结束循环就可以完成需求了。
线程等待
因为线程的调度是随机的无序的,所以当两个线程一起运行时可能会有一些错误,比如下面这个例子:
public class ThreadJoin {public static int count = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for(int i = 0;i < 5000;i++) {count++;}});Thread t2 = new Thread(() -> {for(int i = 0;i < 5000;i++) {count++;}});t1.start();t2.start();Thread.sleep(3000);System.out.println(count);}
}

根据代码的逻辑我们希望每个线程对变量count进行5000次++操作,最后的结果应该是10000,但实际结果并不符合预期,这是因为两个线程在同时进行的过程中可能出现两次++变量只增加一次的情况,这个我们之后在详细分析原因,现在我们只需要让一个线程等待另一个线程执行完就可以避免这个错误,线程等待我们可以使用join()方法。

在主线程中,通过t1线程调用join()方法的意思是,让主线程等待t1线程执行完之后在执行之后的代码,此时就控制了t1与t2线程的执行顺序了。
获取线程实例
通过Thread.currentThread()就可以获取到该线程的实例:

相关文章:
Java多线程编程,Thread类的基本用法讲解
文章目录如何创建一个线程start 与 run线程休眠线程中断线程等待获取线程实例如何创建一个线程 之前我们介绍了什么是进程与线程,那么我们如何使用代码去创建一个线程呢?线程操作是操作系统中的概念,操作系统内核实现了线程这样的机制&#…...
TIA博途Wincc_多路复用变量的使用方法示例(实现多台相同设备参数的画面精简)
TIA博途Wincc_多路复用变量的使用方法示例(实现多台相同设备参数的画面精简) 使用多路复用变量的好处: 当项目中存在多个相同的设备(例如:变频器、电机等),对这些设备在HMI上进行监控或修改参数时,不再需要逐个建立画面或IO域等,只需通过单个画面或IO域组合即可实现对…...
关于console你不知道的那些事
看到标题,大家会不会想,我都在前端岗位叱咤风云这么多年了, console 这个玩意用你讲 但是, 今天我将带你看到不一样的 console, 可以带来更多的帮助 了解 console 什么是 console ? console 其实是 JavaScript 内的一个原生对象。内部存储的方法大部…...
Java设计模式-责任链模式
1 概述 在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同…...
顺序表设计循环队列
使用顺序表来设计队列的最大优势是顺序表有可以定位元素的下标。 并且可以以Mod来使数组下标循环 #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> typedef int CQDataType; typedef struct { int* array; in…...
UEFI 基础教程 (十四) - 设置默认启动项为UEFI Shell
一 编写源代码 OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c UINTN BootOptionPriority ( CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption ) { DEBUG ((EFI_D_ERROR," [CSDN] BootOptionPriority %S .\n", BootOption->Description)); if (StrCmp (…...
python编程:判断一个数是否是超级素数
请定义一个函数,实现判断一个数是否是超级素数,并输出判断的结果。 一、编程题目 我们都知道,素数是除了1之外只能被自身整数的数,1除外。如果一个素数,去除一位、两位或多位后依然是素数,则我们称该素数为超级素数。…...
雷迪RD8200管线探测仪参数/管线仪使用方法/管线仪说明书
预防损坏和工作效率是我们客户面临的最大挑战 全新的 RD8200可以解决这些问题。这是我们功能优秀的精密管线仪系列,设计时充分考虑了操作员的需要。 预防损坏的专业选择 速度、准确性和可靠的性能 易于设置和使用 阳光下可读的显示屏、高性能的音频系统和用于嘈杂…...
会话共享保存到redis
1. 安装redis服务 [rootdb01 ~]# yum -y install redis 2. 配置redis服务 修改配置文件可以让其他服务器远程连接 127.0.0.1:6379 # 默认只能本地连接 [rootdb01 ~]# vim /etc/redis.conf [rootdb01 ~]# grep 172.16.1.51 /etc/redis.conf bind 127.…...
python 曲线平滑处理——方法总结(Savitzky-Golay 滤波器、make_interp_spline插值法和convolve滑动平均滤波)
文章目录1 插值法对曲线平滑处理1.1 插值法的常见实现方法1.2 拟合和插值的区别1.3 代码实例2 Savitzky-Golay 滤波器实现曲线平滑2.1 问题描述2.2 Savitzky-Golay 滤波器--调用讲解2.3 Savitzky-Golay 曲线平滑处理 示例2.4 Savitzky-Golay原理剖析3 基于Numpy.convolve实现滑…...
小驰私房菜_10_camx Otp Dump
#小驰私房菜# #camx# #Otp Dump# 本篇文章分下面几点展开: 1、otp dump的目的? 2、如何打开otp dump开关? 3、otp guide手册如何查看? 4、如何初步确认dump 出来的数据是否正确? 一、otp dump的目的 关于otp的一些概念,这里就不做过多的介绍了,不了解的同学,可以先去…...
priority_queue(堆)干货归纳+用法示例
10.priority_queue一.priority_queue(堆Heap)简介1.堆的特点:2.使用场景:二.成员函数1.构造函数:priority_queue构造函数方式:2.push()函数:向priority_queue中插入一个元素:3.pop()…...
miniprogram-to-uniapp使用指南(各种小程序项目转换为uni-app项目)
小程序分类:uni-app qq小程序 支付宝小程序 百度小程序 钉钉小程序 微信小程序 小程序转成uni_app 小程序转为uni_app 小程序转uni_app 小程序转换 工具现在支持npm全局库、HBuilderX插件两种方式使用,任君选择,HBuilderX插件地址:…...
BZOJ2720: [Violet 5]列队春游 【概率与期望】
题意自行理解,先讲一下概率和期望怎么算 概率 概率准确的定义自行百度,这里就不赘述了 概率的计算其实很简单,就是将符合条件的情况除以总共的情况 下面以掷骰子为例: 问题:将一个骰子掷出,666朝上的概率是多少 …...
脉诊之脉象——平脉,常见病脉,七绝脉
平脉与病脉诊脉纲领平人脉象常见病脉浮脉沉脉迟脉数脉虚脉实脉涩脉洪脉细脉滑脉弦脉紧脉长脉短脉弱脉芤脉结脉代脉七绝脉釜沸脉鱼翔脉虾游脉屋漏脉雀啄脉解索脉弹石脉预后诊脉纲领 脉跳动的力度:有力者,气足也。无力者,气不足也。 脉…...
第05章_存储引擎
第05章_存储引擎 🏠个人主页:shark-Gao 🧑个人简介:大家好,我是shark-Gao,一个想要与大家共同进步的男人😉😉 🎉目前状况:23届毕业生,目前在某…...
【新2023Q2押题JAVA】华为OD机试 - 挑选字符串
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:挑选字符串 题目 给定a-z,…...
职场「OKR」,魔幻又内卷
个人习惯称之为【O-KR-KPI】组合; 01从进厂实习那天开始,就接触了KPI的概念; 互联网公司,年初入职,可能因为那天是周五,又赶上月底,少不了要把KPI搬出来折腾一番; 天时,…...
mysql8计算商家距离,按照由近及远排序
要计算商家距离并按照距离排序,可以使用MySQL 8中的空间函数和索引。以下是一个例子: 创建商家表 CREATE TABLE merchants (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50),location POINT,SPATIAL INDEX (location) ) EngineInnoDB;插入商家数据…...
c语言函数使用记录
1.sscanf函数的用法sscanf():将 C 语言字符串中数据按 指定的格式 将数据存储在对应的参数中。// sscanf() 会从 buffer 里读进数据,依照 format 的格式将数据写入到 argument 里, //注意这里的 argument 需要使用地址符号 // 转换格式参考 s…...
编程小白的第一课:用快马AI零代码基础创建个人技能展示网站
作为一个刚接触编程的新手,我最近尝试用InsCode(快马)平台做了一个个人技能展示网站。整个过程比我预想的简单很多,特别适合零基础的同学上手。下面分享我的具体实现过程和心得: 项目规划与结构设计 刚开始完全不懂代码结构,但平台…...
Phi-3-mini-4k-instruct-gguf实战案例:用轻量模型替代Llama3-8B做高频短任务降本
Phi-3-mini-4k-instruct-gguf实战案例:用轻量模型替代Llama3-8B做高频短任务降本 1. 为什么选择轻量模型 在AI应用落地的过程中,我们常常面临一个困境:大模型效果虽好,但部署成本高、响应速度慢。特别是在处理大量高频短任务时&…...
Qt5.14.2与VS2019整合开发避坑指南(从安装到第一个GUI项目)
Qt5.14.2与VS2019整合开发避坑指南(从安装到第一个GUI项目) 在Windows平台进行Qt开发时,Visual Studio作为强大的IDE环境,与Qt框架的结合能够显著提升开发效率。本文将深入剖析Qt5.14.2与VS2019整合过程中的关键环节,从…...
ESXI系统安装全流程详解:从U盘启动到网络配置
1. 制作ESXI系统U盘启动盘 准备一个容量至少8GB的U盘,建议使用USB3.0接口的高速U盘,这样写入速度会快很多。我实测过,用USB2.0的U盘写入一个ESXI镜像可能需要20分钟,而USB3.0通常5分钟就能搞定。 首先需要下载两个关键文件&#x…...
DocRes实战指南:高效统一文档图像修复任务的完整解决方案
DocRes实战指南:高效统一文档图像修复任务的完整解决方案 【免费下载链接】DocRes [CVPR 2024] DocRes: A Generalist Model Toward Unifying Document Image Restoration Tasks 项目地址: https://gitcode.com/gh_mirrors/do/DocRes DocRes是一个革命性的通…...
深圳小学数学期末试卷创新题型引热议,数学与文学跨界融合成焦点
1. 当数学题遇上古诗词:深圳试卷创新设计背后的教育逻辑 深圳某区五年级数学期末卷上的一道"跨界题"最近在家长群炸开了锅。题目要求学生分析函数单调性后,将其与《琵琶行》中琵琶女的情感变化对应起来。这种"数学古诗文"的混搭模式…...
Hunyuan-MT-7B像素翻译终端效果实测:中英日韩四语同屏对照演示
Hunyuan-MT-7B像素翻译终端效果实测:中英日韩四语同屏对照演示 1. 产品概览与核心特色 1.1 像素化翻译新体验 Pixel Language Portal(像素语言跨维传送门)是一款基于Tencent Hunyuan-MT-7B大模型构建的创新翻译工具。与传统翻译软件不同&a…...
告别兼容性烦恼,让老旧应用在现代浏览器中“无缝”运行
在数字化转型的浪潮中,企业的技术架构往往承载着历史的痕迹。当我们享受着现代浏览器带来的极速体验与丰富扩展时,一个不容忽视的挑战正悄然影响着员工的工作效率与IT运维的平静——那就是“传统浏览器支持”问题。这并非一个遥不可及的技术概念…...
Qwen3.5-2B图文理解实战:上传建筑平面图,自动标注房间功能与面积
Qwen3.5-2B图文理解实战:上传建筑平面图,自动标注房间功能与面积 1. 引言:当AI遇见建筑设计 想象一下这样的场景:你刚拿到一张复杂的建筑平面图,需要快速标注每个房间的功能和面积。传统方法可能需要花费数小时手动测…...
LoRA训练助手GPU显存优化:Qwen3-32B INT4量化后仅需9.2GB显存稳定运行
LoRA训练助手GPU显存优化:Qwen3-32B INT4量化后仅需9.2GB显存稳定运行 1. 引言:当大模型遇见显存焦虑 如果你尝试过在个人电脑上运行大语言模型,大概率会遇到一个令人头疼的问题:显存不足。特别是像Qwen3-32B这样拥有320亿参数的…...
