Java多线程-第20章
Java多线程-第20章
1.创建线程
Java是一种支持多线程编程的编程语言。多线程是指在同一程序中同时执行多个独立任务的能力。在Java中,线程是一种轻量级的子进程,它是程序中的最小执行单元。Java的多线程编程可以通过两种方式实现:继承Thread类或实现Runnable接口。
-
继承Thread类:
class MyThread extends Thread {public void run() {// 线程执行的代码} }
创建并启动线程:
MyThread myThread = new MyThread(); myThread.start(); // 启动线程
-
实现Runnable接口:
class MyRunnable implements Runnable {public void run() {// 线程执行的代码} }
创建并启动线程:
MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); // 启动线程
所有的程序都是通过main
方法开始执行的。当一个Java程序启动时,JVM(Java虚拟机)会自动创建一个主线程,该线程负责执行main
方法。在多线程编程中,你可以创建额外的线程来执行其他任务。
Java提供了一些关键字和方法来控制线程的执行,其中一些关键字包括:
synchronized
:用于控制多个线程访问共享资源时的同步问题。wait()
、notify()
、notifyAll()
:用于实现线程间的通信和协调。sleep(long milliseconds)
:让线程休眠一段时间。join()
:等待一个线程终止。yield()
:让出CPU执行权,让其他线程执行。
多线程编程的主要挑战之一是避免竞态条件(Race Condition)和死锁(Deadlock)。竞态条件发生在多个线程试图同时访问和修改共享数据时,而死锁则是线程相互等待对方释放资源,导致所有线程都无法继续执行的情况。
线程的状态有以下几种:
- 新建(New): 线程已经创建,但还没有开始执行。
- 就绪(Runnable): 线程可以开始执行,等待CPU时间片。
- 运行(Running): 线程正在执行。
- 阻塞(Blocked): 线程被阻塞,等待某个事件的发生。
- 死亡(Terminated): 线程执行完成。
请注意,Java的多线程编程也有一些高级的概念和工具,如线程池、Callable和Future等,用于更灵活地处理多线程任务。
实例1:让线程循环打印1-10的数字
实例2:让窗口中的图标动起来
2.线程的生命周期
Java线程的生命周期描述了一个线程从创建到运行再到结束的整个过程,它包括多个状态,每个状态代表了线程在不同阶段的状态。Java线程的生命周期可以分为以下几个状态:
- 新建状态(New):
- 当线程对象被创建时,它处于新建状态。
- 此时,线程还没有开始执行。
- 就绪状态(Runnable):
- 当线程调用
start()
方法后,线程进入就绪状态。 - 此时,线程已经准备好运行,等待获取CPU时间片。
- 当线程调用
- 运行状态(Running):
- 当就绪状态的线程获取到CPU时间片时,线程进入运行状态。
- 此时,线程正在执行其任务。
- 阻塞状态(Blocked):
- 线程在运行过程中,可能由于某些原因需要暂时放弃CPU时间片,进入阻塞状态。
- 典型的例子包括等待I/O完成、等待获取锁、等待通知等。
- 当阻塞条件解除时,线程会重新进入就绪状态。
- 等待状态(Waiting):
- 线程在等待某个条件满足时,会进入等待状态。
- 调用
Object.wait()
、Thread.join()
、LockSupport.park()
等方法可以使线程进入等待状态。 - 等待状态的线程需要其他线程通知或中断才能继续执行。
- 超时等待状态(Timed Waiting):
- 线程在等待一段时间后会进入超时等待状态。
- 调用带有超时参数的
Object.wait()
、Thread.sleep()
、Thread.join()
等方法会导致线程进入超时等待状态。
- 终止状态(Terminated):
- 线程执行完任务或者发生了未捕获的异常时,线程进入终止状态。
- 一个终止状态的线程不能再次启动。
这些状态构成了线程的生命周期,如下图所示:
New -> Runnable -> (Running) -> Blocked -> (Runnable) -> (Terminated)\-> Waiting -> (Runnable) -> (Terminated)\-> Timed Waiting -> (Runnable) -> (Terminated)
注意,生命周期中的括号表示这些状态可能是短暂的,线程可能在运行、等待、超时等待等状态间切换。在实际的多线程应用中,正确地管理线程生命周期是至关重要的,以避免潜在的问题,如死锁、竞态条件等。
3.操作线程的方法
4.1线程的休眠
线程休眠是通过Thread.sleep(long milliseconds)
方法实现的。这个方法让当前正在执行的线程在指定的时间内进入休眠状态(即暂停执行),单位是毫秒。在指定时间过去或者线程被中断时,线程将恢复执行。
方法签名为:
public static native void sleep(long millis) throws InterruptedException;
millis
:休眠时间,以毫秒为单位。
注意,sleep
方法可能抛出InterruptedException
异常,因为线程在休眠时可以被其他线程中断。在处理中断时,可以选择捕获该异常并处理,或者将异常继续传播出去。
4.2线程的加入
在Java中,可以使用join()
方法来等待一个线程完成其执行。join()
方法的作用是使当前线程等待调用join()
方法的线程执行结束,然后再继续执行当前线程。
方法签名为:
public final void join() throws InterruptedException;
或者可以使用带有超时参数的join(long millis)
方法:
javaCopy code
public final synchronized void join(long millis) throws InterruptedException;
millis
:等待的最大时间(以毫秒为单位)。
以下是一个简单的例子,演示了线程的加入:
class MyThread extends Thread {public void run() {for (int i = 1; i <= 5; i++) {System.out.println("Task " + i + " in progress by " + Thread.currentThread().getName());try {// 模拟任务执行时间Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class JoinExample {public static void main(String[] args) {MyThread thread1 = new MyThread();MyThread thread2 = new MyThread();// 启动线程1thread1.start();try {// 等待线程1执行完成,然后再继续执行主线程thread1.join();} catch (InterruptedException e) {e.printStackTrace();}// 启动线程2thread2.start();// 主线程继续执行System.out.println("Main thread continues its work.");}
}
在这个例子中,主线程启动了thread1
,然后调用thread1.join()
等待thread1
执行完成,接着启动了thread2
。由于join()
方法会使主线程等待被调用的线程执行完成,所以在这个例子中主线程会等待thread1
执行完成后再启动thread2
。
4.3线程的中断
线程的中断是一种线程间的协作机制,它允许一个线程通知另一个线程,以请求它停止正在执行的任务。线程的中断通过调用interrupt()
方法来触发。
-
中断线程:
-
使用
interrupt()
方法中断线程。Thread myThread = new MyThread(); myThread.start(); // ... myThread.interrupt(); // 中断线程
-
interrupt()
方法会设置线程的中断标志位,但并不会立即停止线程的执行。线程需要检查自己的中断状态并在适当的时候终止执行。
-
-
检查中断状态:
-
使用
Thread.interrupted()
方法检查当前线程的中断状态,并清除中断状态。if (Thread.interrupted()) {// 线程已被中断,执行相应的处理 }
-
或者使用
isInterrupted()
方法检查线程的中断状态而不清除中断状态。if (myThread.isInterrupted()) {// 线程已被中断,执行相应的处理 }
-
-
处理中断:
-
在线程的执行过程中,可以通过检查中断状态来决定是否停止执行。
public void run() {while (!Thread.interrupted()) {// 执行任务} }
-
或者在抛出
InterruptedException
异常的地方处理中断。public void run() {try {while (true) {// 执行任务if (Thread.interrupted()) {throw new InterruptedException();}}} catch (InterruptedException e) {// 处理中断异常} }
-
在处理中断时,可以选择终止线程的执行,或者采取其他适当的措施。
-
中断通常用于优雅地停止线程,而不是强制终止线程。这种协作的方式允许线程在中断请求到来时,完成正在进行的工作,并进行清理工作,提高程序的健壮性。
实例3:单击按钮停止进度条滚动
4.4线程的礼让
线程的礼让是指一个线程表明自己愿意让出当前的CPU执行时间,以便让其他线程有机会执行。我们可以使用Thread.yield()
方法来实现线程的礼让。
方法签名为:
public static native void yield();
Thread.yield()
方法是一个静态方法,调用它的线程会让出一些时间片,以便其他具有相同或更高优先级的线程有机会执行。然而,yield()
方法并不能保证线程会让出CPU执行权,它只是向调度器发出一个提示。
5.线程的优先级
线程调度器使用线程的优先级来决定哪个线程应该优先执行。线程的优先级是一个整数值,范围从Thread.MIN_PRIORITY
(1)到Thread.MAX_PRIORITY
(10)。默认情况下,每个线程的优先级都是Thread.NORM_PRIORITY
(5)。
线程的优先级可以通过setPriority(int priority)
方法进行设置。该方法必须在启动线程之前调用。
以下是设置线程优先级的例子:
class MyThread extends Thread {public void run() {for (int i = 1; i <= 5; i++) {System.out.println("Task " + i + " in progress by " + Thread.currentThread().getName());}}
}public class PriorityExample {public static void main(String[] args) {MyThread thread1 = new MyThread();MyThread thread2 = new MyThread();// 设置线程1的优先级为最高thread1.setPriority(Thread.MAX_PRIORITY);// 启动线程1thread1.start();// 启动线程2thread2.start();}
}
在这个例子中,thread1
的优先级被设置为最高(Thread.MAX_PRIORITY
),而thread2
使用默认的优先级。在运行时,具有更高优先级的线程更有可能被调度执行,但并不能保证绝对顺序。
注意,线程优先级的调整并不是在所有平台上都能生效的,而且过度依赖线程优先级可能导致可移植性问题。在实际应用中,更重要的是编写稳健的多线程代码,而不是过分关注线程优先级。
实例4:观察不同优先级的线程执行完毕顺序
6.线程同步
线程同步是一种机制,用于防止多个线程同时访问共享资源,从而避免数据不一致性和竞态条件。在Java中,主要的线程同步机制包括使用synchronized
关键字、wait()
、notify()
和notifyAll()
方法、以及Lock
和Condition
接口等。
6.1线程安全
线程安全是指多个线程访问某个共享资源时,不会出现不确定的结果或导致不一致性的情况。在多线程环境中,如果没有适当的同步机制,共享的数据结构可能会被多个线程同时修改,从而导致数据不一致或其他问题。确保线程安全是多线程编程中非常重要的一个方面。
以下是一些确保线程安全的常见方式:
-
使用同步方法: 在方法上使用
synchronized
关键字,确保一次只有一个线程可以执行该方法。public synchronized void synchronizedMethod() {// 同步的代码块 }
-
使用同步代码块: 在代码块中使用
synchronized
关键字,确保一次只有一个线程可以执行同步代码块。public void someMethod() {// 非同步代码synchronized (lockObject) {// 同步的代码块}// 非同步代码 }
-
使用
java.util.concurrent
包中的线程安全类: Java提供了一些线程安全的数据结构,如ConcurrentHashMap
、CopyOnWriteArrayList
等。Map<String, String> concurrentMap = new ConcurrentHashMap<>(); List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
-
使用
Lock
和Condition
: 使用Lock
接口及其实现类来提供更细粒度的同步控制。Lock lock = new ReentrantLock(); Condition condition = lock.newCondition();lock.lock(); try {// 临界区的代码 } finally {lock.unlock(); }
-
使用
volatile
关键字:volatile
关键字可以保证变量的可见性,但不能解决复合操作的原子性问题。private volatile boolean flag = false;
-
使用原子类:
java.util.concurrent.atomic
包中提供了一些原子类,如AtomicInteger
、AtomicLong
等,用于执行原子操作。AtomicInteger atomicInt = new AtomicInteger(0); atomicInt.incrementAndGet();
确保线程安全是一个综合性的问题,需要在设计阶段考虑,并采用适当的同步措施。选择合适的同步机制取决于具体的应用场景和性能要求。在设计和实现多线程程序时,充分了解并考虑线程安全性是至关重要的。
实例5:开发线程安全的火车售票系统
6.2线程同步机制
线程同步机制是一组用于确保多个线程访问共享资源时不会发生竞态条件和数据不一致的技术。以下是一些常见的线程同步机制:
-
synchronized 关键字:
synchronized
关键字用于修饰方法或代码块,确保在同一时刻最多只有一个线程能够进入被synchronized
修饰的方法或代码块。
// 同步方法 public synchronized void synchronizedMethod() {// 同步的代码块 }// 同步代码块 public void someMethod() {// 非同步代码synchronized (lockObject) {// 同步的代码块}// 非同步代码 }
-
Lock 和 Condition 接口:
Lock
接口提供了比synchronized
更灵活的锁定机制。通过ReentrantLock
实现类,可以使用lock()
和unlock()
方法来控制临界区的访问。Condition
接口用于在Lock
上创建条件变量,通过await()
、signal()
和signalAll()
方法实现更灵活的线程通信。
Lock lock = new ReentrantLock(); Condition condition = lock.newCondition();lock.lock(); try {// 临界区的代码 } finally {lock.unlock(); }
-
volatile 关键字:
volatile
关键字用于声明变量,确保线程之间对该变量的写入和读取操作是可见的。它不提供原子性,仅仅保证了可见性。
private volatile boolean flag = false;
-
Atomic 类:
java.util.concurrent.atomic
包中提供了一组原子类,如AtomicInteger
、AtomicLong
,用于执行原子操作,避免竞态条件。
AtomicInteger atomicInt = new AtomicInteger(0); atomicInt.incrementAndGet();
-
ReadWriteLock 接口:
ReadWriteLock
接口提供了读写锁,允许多个线程同时读取共享资源,但只允许一个线程写入。
ReadWriteLock rwLock = new ReentrantReadWriteLock(); rwLock.readLock().lock(); // 读取共享资源的操作 rwLock.readLock().unlock();rwLock.writeLock().lock(); // 写入共享资源的操作 rwLock.writeLock().unlock();
这些机制可以根据具体的应用场景选择使用,每种机制都有其适用的情况。合理选择同步机制可以提高多线程程序的性能和可维护性,避免潜在的并发问题。
相关文章:

Java多线程-第20章
Java多线程-第20章 1.创建线程 Java是一种支持多线程编程的编程语言。多线程是指在同一程序中同时执行多个独立任务的能力。在Java中,线程是一种轻量级的子进程,它是程序中的最小执行单元。Java的多线程编程可以通过两种方式实现:继承Threa…...

寿险公司通过开源治理保障数字创新,安全打通高质量服务新通道
某寿险公司致力于为消费者提供人性化的产品和服务,在中国保险市场中始终保持前列。该寿险公司以挖掘和满足客户需求为出发点,从产品开发、渠道销售、运营流程和售后服务等各环节,借助数字化工具,不断地努力探索并提升服务品质。 精…...

SpringBoot中的部分注解
1.SpringBoot/spring SpringBootApplication: 包含Configuration、EnableAutoConfiguration、ComponentScan通常用在主类上; Repository: 用于标注数据访问组件,即DAO组件; Service: 用于标注业务层组件; RestController: 用…...
蓝桥杯-02-蓝桥杯C/C++组考点与14届真题
文章目录 蓝桥杯C/C组考点与14届真题参考资源C/C组考点1. 组别2. 竞赛赛程3. 竞赛形式4. 参赛选手机器环境5. 试题形式5.1. 结果填空题5.2. 编程大题 6. 试题考查范围7. 答案提交8. 评分9. 样题样题 1:矩形切割(结果填空题)样题 2:…...
计算机杂谈系列精讲100篇-【计算机应用】关于TensorFlow和PyTorch的一些看法
目录 前言 知识储备 PyTorch使用高频代码 导入包和版本查询...
Uni-App知识点
文章目录 一、事件总线二、什么是事件总线三、触发事件1、监听事件2、只监听一次3、移除监听4、触发事件注意事项5、代码示例6、注意事项 一、事件总线 除了父子组件传参之外,兄弟组件之间共享信息也是我们经常会遇到的。如果遇到这类问题,我们现在可以…...

Postman如何使用(四):接口测试
一.接口 1.程序内部接口:方法与方法之间,模块与模块之间的交互,程序内部抛出的接口,比如bbs系统,有登录模块,发帖模块等等,那你要发帖就必须先登录,那么这两个模块就得有交互&#…...

【Qt绘图】之绘制坦克
使用绘图事件,绘制坦克。 效果 效果很逼真,想象力,有没有。 示例 代码像诗一样优雅,有没有。 包含头文件 #include <QApplication> #include <QWidget> #include <QPainter>绘制坦克类 class TankWidge…...

【机器视觉技术栈】- 机器视觉基础
1.1 为什么采用机器视觉 人眼与机器视觉对比 人眼机器视觉精确性差,64灰度级,不能分辨小于100微米的目标强,256灰度级,可检测微米级目标速度慢,无法看清间隔小于40毫秒的运动目标快,快门时间可达10微秒适…...
Arkts开发UIAbility组件生命周期启动模式开发详解【鸿蒙专栏-19】
文章目录 HarmonyOS UIAbility组件详解UIAbility组件概述声明配置UIAbility组件生命周期Create状态WindowStageCreate和WindowStageDestroy状态Foreground和Background状态Destroy状态UIAbility组件启动模式Singleton启动模式Standard启动模式Specified启动模式HarmonyOS UIAbi…...

力扣295. 数据流的中位数(java,堆解法)
Problem: 295. 数据流的中位数 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 由于该题目的数据是动态的我们可以维护两个堆来解决该问题 1.维护一个大顶堆,一个小顶堆 2.每个堆中元素个数接近n/2;如果n是偶数,两个堆中的数据个数…...

open3d-点云及其操作
open3d提供了一个专门用于点云的数据结构 PointCloud。 class PointCloud(Geometry3D):color # 颜色normals # 法向量points # 点云def __init__(self, *args, **kwargs):"""__init__(*args, **kwargs)Overloaded function.1. __init__(self: open3d.cpu.py…...

无人机助力电力设备螺母缺销智能检测识别,python基于YOLOv7开发构建电力设备螺母缺销高分辨率图像小目标检测系统
传统作业场景下电力设备的运维和维护都是人工来完成的,随着现代技术科技手段的不断发展,基于无人机航拍飞行的自动智能化电力设备问题检测成为了一种可行的手段,本文的核心内容就是基于YOLOv7来开发构建电力设备螺母缺销检测识别系统…...

如何使用Python的Open3D开源库进行三维数据处理
简介 在本文中,我提供了一个关于如何使用Python的Open3D库(一个用于3D数据处理的开源库)来探索、处理和可视化3D模型的快速演练。 使用Open3D可视化的3D模型(链接https://sketchfab.com/3d-models/tesla-model-s-plaid-9de8855fa…...
HarmonyOS应用开发者基础认证试题
判断题 1.Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件。一个应用可以包含一个或多个Ability。(true) 2.Tabs组件仅可包含子组件TabsContent,每一个页签对应一个内容视图即TabContet组件。(true) 3.使用http模块发起网络请求时&#…...
Android Camera2开启电子防抖(EIS)和光学防抖(OIS)
刚好当前项目有录像功能,使用了第三方框架是基于Camera2引擎开发,当使用 Camera2 API 开发相机应用时,启用和关闭 EIS(电子防抖)是一个重要的功能。EIS 可以帮助减少相机拍摄时的抖动,从而提高图像和视频的…...
劲爆:Sam Altman 回归CEO专访确认Q*的存在
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

Electronica慕尼黑电子展 Samtec团队与21ic分享虎家产品与方案
【摘要/前言】 “希望但凡是能够使用到连接器的场合都有Samtec的身影” 在慕尼黑上海电子展现场,Samtec华东区销售经理章桢彦先生在与21ic副主编刘岩轩老师的采访中,如是说道。这是一种愿景,更是Samtec的努力方向。短短一句话,…...

Vue基本使用(一)
📑前言 本文主要是【Vue】——Vue基本使用的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一句&#x…...
Android:BackStackRecord
BackStackRecord:fragment回退栈,继承自FragmentTransaction,并且实现了OpGenerator接口,OpGenerator接口用来添加或弹出事务的,后面会提到。 从《Android:从源码看FragmentManager如何工作》文章知道,每次beginTransaction会创建一个BackStackRecord对象,改对象持有f…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...