当前位置: 首页 > news >正文

Java并发编程——上下文切换、死锁、资源限制

文章目录

    • 1.1上下文切换
      • (1)上下文切换的概念
      • (2)多线程一定比单线程快吗?
      • (3)测量上下文切换
        • 如何减少上下文切换
    • 1.2 死锁
      • (1)死锁的定义
      • (2)死锁产生的四个必要条件
      • (2)死锁的解决方法
    • 1.3 资源限制的挑战
      • (1)资源限制的定义
      • (2)资源限制引发的问题
      • (3)解决资源限制的方法
      • (4)在资源限制下的并发编程

并发编程旨在通过多线程执行任务来提高程序的运行效率,但实现并发并不总是能带来预期的速度提升。多线程的执行效率受到多个因素的影响,主要包括上下文切换、死锁和硬件/软件资源限制等问题。本章介绍了这些挑战以及相应的解决方案。

1.1上下文切换

(1)上下文切换的概念

  • 定义:上下文切换是指CPU在不同线程之间切换执行时,需要保存当前线程的状态,并加载下一个线程的状态。

  • 原理:单核处理器通过时间片(几十毫秒)分配CPU时间,使得多个线程看起来像是并行执行的。上下文切换会带来性能开销,因为每次切换都需要保存和恢复线程的上下文。

    例子:通过读两本书来类比,类似于在读一本英文技术书时,每次查字典时都需要记住当前进度并切换任务,这种切换会影响效率。

(2)多线程一定比单线程快吗?

  • 测试代码:比较并发和串行执行相同的累加任务的时间。
public class ConcurrencyTest {private static final long count = 10000l;public static void main(String[] args) throws InterruptedException {concurrency();serial();}private static void concurrency() throws InterruptedException {long start = System.currentTimeMillis();Thread thread = new Thread(new Runnable() {@Overridepublic void run() {int a = 0;for (long i = 0; i < count; i++) {a += 5;}}});thread.start();int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;thread.join();System.out.println("concurrency :" + time+"ms,b="+b);}private static void serial() {long start = System.currentTimeMillis();int a = 0;for (long i = 0; i < count; i++) {a += 5;}int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;System.out.println("serial:" + time+"ms,b="+b+",a="+a);}
}

测试结果:

在这里插入图片描述

  • 结论:并发执行不一定比串行快,特别是任务次数较少时。原因是线程的创建和上下文切换的开销。测试表明,当任务量不够大时,线程的管理和切换反而可能让程序变慢。

(3)测量上下文切换

  • 使用工具

    • Lmbench3:测量上下文切换的时长。
    • vmstat:测量上下文切换的次数。

    示例命令

    vmstat 1
    

在这里插入图片描述

输出中的 CS(Context Switches)表示每秒的上下文切换次数。

如何减少上下文切换

解决方案:

  1. 无锁并发编程:避免锁竞争,减少上下文切换。通过设计合适的数据分割和线程划分,减少锁的使用。
  2. CAS(Compare And Swap)算法:Java的Atomic包通过CAS实现无锁的并发操作。
  3. 使用最少的线程:避免创建不必要的线程,避免过多线程造成的上下文切换。
  4. 协程:通过协程在单线程中实现任务切换,从而避免多线程的上下文切换开销。

1.2 死锁

(1)死锁的定义

  • 死锁是指两个或多个线程互相等待对方释放锁,从而导致无法继续执行。

    示例代码

    public class DeadLockDemo {private static String A = "A";private static String B = "B";public static void main(String[] args) {new DeadLockDemo().deadLock();}private void deadLock() {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (A) {try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }synchronized (B) {System.out.println("1");}}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (B) {synchronized (A) {System.out.println("2");}}}});t1.start();t2.start();}
    }

代码中的Thread-1Thread-2相互等待对方的锁,造成死锁。

(2)死锁产生的四个必要条件

  • 互斥(Mutual Exclusion):资源只能被一个线程或进程占有,且其他线程或进程必须等待。例如,一个线程占用某个锁,其他线程就无法访问该资源,直到锁被释放。
  • 占有且等待(Hold and Wait):线程或进程已经持有某些资源,同时又请求其他资源,而这些资源当前被其他线程或进程占用。
  • 不可剥夺(No Preemption):已经分配给线程或进程的资源,在没有释放之前不能被其他线程或进程强行抢占。只有线程或进程自己释放资源,其他线程才能获得资源。
  • 循环等待(Circular Wait):存在一个资源的等待链,其中每个线程或进程都在等待下一个线程或进程所持有的资源,形成一个闭环。

(2)死锁的解决方法

  • 破坏循环等待条件
    资源的顺序分配:最常见的解决方法是对资源加锁时,按照一定的顺序来申请资源,避免出现循环等待。例如,为每个资源分配一个唯一的编号,然后线程总是按照资源编号的顺序来申请资源。如果线程按顺序申请资源,就不会出现循环等待的情况。
  • 破坏占有且等待条件
    一次性申请所有资源:要求线程在执行时一次性申请它需要的所有资源,而不是在持有一部分资源时,再去申请其他资源。这样可以避免线程在持有部分资源的同时等待其他资源,从而避免占有且等待条件。
  • 破坏非抢占条件
    抢占资源:当线程申请资源失败时,系统可以强制剥夺线程持有的资源并将其返回给资源池。被抢占的线程可以在稍后重新尝试获取资源。这种方法通过破坏非抢占条件来避免死锁。
  • 破坏互斥条件
    使用共享资源:通过将资源的互斥性降低,即允许多个线程共享资源,来避免死锁。比如,对于读写操作,可以使用 读写锁,使得多个线程可以同时读取共享资源,但写操作仍然是独占的。此方法只适用于资源可以共享的场景,通常是读取操作较多的情况。
  • 银行家算法
    详情可见 银行家算法:死锁避免的经典策略

1.3 资源限制的挑战

(1)资源限制的定义

资源限制是指硬件或软件资源(如带宽、CPU、内存、数据库连接数等)的限制,可能会影响程序并发执行的效果。资源限制可能导致并发执行时,程序反而执行更慢。

(2)资源限制引发的问题

  • 如果并发的代码段依赖于硬件或软件资源,过多的线程会使得程序反而变慢。例如:
    • 带宽限制:如果有多个线程同时下载文件,而带宽有限,线程多了反而会因为等待带宽而导致执行时间变长。
    • 数据库连接数限制:如果数据库的连接数有限,而线程数过多,则会因为线程被阻塞等待连接,导致程序性能下降。

(3)解决资源限制的方法

  • 硬件资源限制:使用集群并行执行任务,分布式计算框架如HadoopODPS等可以有效利用多台机器的资源。
  • 软件资源限制:使用资源池技术,复用数据库连接池或Socket连接池。

(4)在资源限制下的并发编程

根据资源限制调整并发度。例如,在文件下载程序中,既依赖带宽又依赖硬盘读写速度。如果带宽有限,增加过多线程不会加速下载,反而可能导致过度的上下文切换,增加执行时间。

相关文章:

Java并发编程——上下文切换、死锁、资源限制

文章目录 1.1上下文切换&#xff08;1&#xff09;上下文切换的概念&#xff08;2&#xff09;多线程一定比单线程快吗&#xff1f;&#xff08;3&#xff09;测量上下文切换如何减少上下文切换 1.2 死锁&#xff08;1&#xff09;死锁的定义&#xff08;2&#xff09;死锁产生…...

MS08067练武场--WP

免责声明&#xff1a;本文仅用于学习和研究目的&#xff0c;不鼓励或支持任何非法活动。所有技术内容仅供个人技术提升使用&#xff0c;未经授权不得用于攻击、侵犯或破坏他人系统。我们不对因使用本文内容而引起的任何法律责任或损失承担责任。 注&#xff1a;此文章为快速通关…...

ubuntu文件同步

1. 使用 rsync 同步文件 rsync 是一个常用的文件同步工具&#xff0c;可以在本地或远程系统之间同步文件和目录。 基本用法&#xff1a; rsync -avz /源目录/ 目标目录/-a&#xff1a;归档模式&#xff0c;保留文件属性。-v&#xff1a;显示详细输出。-z&#xff1a;压缩传输…...

C++23 新特性解析

引言&#xff1a;C的持续进化 在ISO C标准委员会的不懈努力下&#xff0c;C23作为继C20后的又一重要迭代版本&#xff0c;带来了十余项核心语言特性改进和数十项标准库增强。本文将深入解析最具实用价值的五大新特性&#xff0c;介绍std::expected到模块化革命。 编译器支持 …...

算法05-堆排序

堆排序详解 堆排序&#xff08;Heap Sort&#xff09;是一种基于二叉堆数据结构的排序算法。它的核心思想是利用堆的性质&#xff08;最大堆或最小堆&#xff09;来实现排序。堆排序分为两个主要步骤&#xff1a;建堆和排序。 1. 什么是堆&#xff1f; 堆是一种特殊的完全二叉…...

Arrays工具类详解

目录 1. Arrays.toString() 方法 2. Arrays.deepToString() 方法 3. Arrays.equals(int[ ] arr1, int[ ] arr2) 方法 4. Arrays.equals(Object[] arr1, Object[] arr2) 方法 5. Arrays.deepEquals(Object[] arr1, Object[] arr2) 方法 6. Arrays.sort(int[] arr) 方法 7…...

无人机图像拼接数据的可视化与制图技术:以植被监测为例

无人机技术在生态环境监测中的应用越来越广泛&#xff0c;尤其是在植被监测领域。通过无人机获取的高分辨率影像数据&#xff0c;结合GIS技术&#xff0c;可以实现对植被覆盖、生长状况等的精确监测与分析。本文将通过一个实际案例&#xff0c;详细讲解无人机图像拼接数据的可视…...

在 debian 12 上安装 mysqlclient 报错

报错如下 Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple Collecting mysqlclientUsing cached https://pypi.tuna.tsinghua.edu.cn/packages/61/68/810093cb579daae426794bbd9d88aa830fae296e85172d18cb0f0e5dd4bc/mysqlclient-2.2.7.tar.gz (91 kB)Installi…...

python基础入门:7.1迭代器与生成器

Python迭代器与生成器深度解析&#xff1a;高效处理海量数据的利器 # 大文件分块读取生成器模板 def chunked_file_reader(file_path, chunk_size1024*1024):"""分块读取大文件生成器"""with open(file_path, r, encodingutf-8) as f:while Tru…...

Docker 容器 Elasticsearch 启动失败完整排查记录

背景 在服务器上运行 Docker 容器 es3&#xff0c;但 Elasticsearch 无法正常启动&#xff0c;运行 docker ps -a 发现 es3 处于 Exited (1) 状态&#xff0c;即进程异常退出。 本次排查从错误日志、容器挂载、权限问题、SELinux 影响、内核参数等多个方面入手&#xff0c;最…...

达梦数据使用笔记

相关文档&#xff1a; 达梦官网 达梦技术文档 1.安装完成后在开始菜单中搜索DM 目录&#xff1a;C:\ProgramData\Microsoft\Windows\Start Menu\Programs\达梦数据库 下有所有相关信息 2.数据迁移 https://eco.dameng.com/document/dm/zh-cn/start/mysql_dm.html https:…...

操作系统中的任务调度算法

一、引言 在操作系统中&#xff0c;任务调度算法是核心组件之一&#xff0c;它负责合理分配有限的 CPU 资源&#xff0c;以确保系统的高效运行和良好的用户体验。任务调度的目标是实现公平性、最小化等待时间、提高系统吞吐量&#xff0c;并最大化 CPU 的利用率。不同的任务调…...

Linux 虚拟服务器(LVS)技术详解

一、LVS 概述 Linux 虚拟服务器&#xff08;Linux Virtual Server&#xff0c;简称 LVS&#xff09;是由章文嵩博士开发的一种开源的服务器集群技术&#xff0c;它工作在 Linux 内核空间&#xff0c;为构建高可用、可扩展的网络服务提供了一种高效的解决方案。LVS 可以将多个真…...

AIoT时代来临,物联网技术如何颠覆未来生活?

在这个万物互联的时代&#xff0c;“物联网”&#xff08;IoT&#xff09;正以前所未有的速度改变我们的生活&#xff0c;而“AIoT”则是在物联网基础上融入人工智能技术&#xff0c;赋予设备更高的智能和自主决策能力。随着5G、边缘计算和云技术的不断发展&#xff0c;物联网正…...

C++17 新特性解析

C++17 是 C++ 标准的一个重要更新,它在 C++11/14 的基础上引入了许多新特性,进一步简化了代码编写、提升了性能和类型安全性。以下是 C++17 的主要特性分类介绍: 一、语言核心改进 1. 结构化绑定(Structured Bindings) 允许将元组、结构体或数组的成员直接解包到变量中。…...

嵌入式软件C语言面试常见问题及答案解析(四)

嵌入式软件C语言面试常见问题及答案解析(四) 原本打算将链表相关的面试题整合到一个文档中,奈何写着写着就发现题目比较多,题型也比较丰富,所以导致上一篇已经足够长了,再长也就有点不礼貌了。 所以在这儿继续来总结分享那个面试中遇到的题目,文中的问题和提供的答案或者…...

在 C# 中,处理 Excel 和 PDF 文件的库有很多。以下是一些比较常用的选择

读取 Excel 文件的库 NPOI 用途&#xff1a;可以读取和写入 .xls 和 .xlsx 文件。特点&#xff1a;无需安装 Microsoft Office&#xff0c;支持简单的 Excel 操作&#xff0c;如格式化、公式、图表等。 EPPlus 用途&#xff1a;主要用于 .xlsx 格式&#xff08;Excel 2007 及以…...

绩效归因概述

绩效归因概述 1. 分类2. 基于净值的归因方法2.1 发展背景2.2 择时选股模型 T-M模型2.3 择时选股模型 H-M模型2.4 择时选股模型 C-L模型2.5 风格配置模型-Sharpe2.6 多因子模型 Fama-French32.7 多因子模型 Carhart42.8 多因子模型 Fama-French5 3. 基于持仓的归因方法3.1 发展背…...

Spring Boot 中加载多个 YAML 配置文件

在 Spring Boot 中加载多个 YAML 配置文件是一个常见的需求&#xff0c;通常用于将配置信息分离到多个文件中以便于管理和维护。Spring Boot 提供了灵活的方式来加载多个 YAML 配置文件。 以下是一些方法和步骤&#xff0c;用于在 Spring Boot 应用中加载多个 YAML 配置文件&a…...

厚植创新实力、聚焦生物科技:柏强制药的责任与机遇

在当今快速发展的医药行业中&#xff0c;创新已成为企业竞争的核心动力。贵州柏强制药作为医药领域的佼佼者&#xff0c;正以科技创新为引领&#xff0c;聚焦生物科技领域&#xff0c;不断突破&#xff0c;不仅为人民的健康事业贡献力量&#xff0c;更在激烈的市场竞争中抓住了…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...