【多线程】常见问题简单总结

news2025/2/28 17:19:08

目录

1. 竞态条件(Race Condition)

场景:

解决方法:

2. 死锁(Deadlock)

场景:

解决方法:

3. 线程饥饿(Thread Starvation)

场景:

解决方法:

4. 活锁(Livelock)

场景:

解决方法:


        多线程编程在提高程序性能方面非常有用,但也引入了一系列常见问题,主要包括竞态条件、死锁、线程饥饿和活锁等。以下是这些问题的解释以及如何在Java中解决它们的例子。

1. 竞态条件(Race Condition)

竞态条件发生在两个或多个线程访问共享资源并尝试同时修改它时。这可能导致不一致和不可预测的结果。

场景:

  • 共享资源: 当多个线程访问和修改同一个变量或资源,而没有适当的同步措施时。
  • 非原子操作: 操作如递增一个计数器,这需要读取、修改和写入值,这些步骤在没有同步的情况下会被中断。
  • 先检查后执行: 先检查资源状态,然后根据状态执行操作的模式,如果状态在检查和执行之间被另一个线程改变,会导致问题。

解决方法:

使用同步机制,如synchronized关键字或显式锁(如`ReentrantLock`),来确保一次只有一个线程可以访问共享资源。

Java 示例

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

2. 死锁(Deadlock)

死锁是指两个或多个线程永远等待对方释放锁的情况。这通常发生在每个线程都持有一个锁并尝试获取其他线程已持有的锁时。

场景:

  • 互斥条件: 程序中的多个线程需要同时锁定多个资源。
  • 请求和保持条件: 线程已经持有至少一个资源,并且正在等待获取额外的资源,这些资源可能被其他已经锁定了它们的线程持有。
  • 不剥夺条件: 资源被线程持有,直到自愿释放,不能被强制剥夺。
  • 循环等待条件: 发生在一组线程中,每个线程都在等待下一个线程所持有的资源。

解决方法:

避免嵌套锁,使用定时锁(尝试锁),或者以一致的顺序获取锁。

Java 示例

public class Account {
    private int balance = 10000;

    // Transfer method with ordered locks to avoid deadlock
    public void transfer(Account from, Account to, int amount) {
        synchronized (from) { // First lock
            synchronized (to) { // Second lock
                if (from.balance >= amount) {
                    from.balance -= amount;
                    to.balance += amount;
                }
            }
        }
    }
}

3. 线程饥饿(Thread Starvation)

线程饥饿发生在低优先级的线程长时间得不到执行,因为高优先级的线程一直占用CPU资源。

场景:

  • 优先级不当: 当一个高优先级的线程不断地被调度,而低优先级的线程得不到足够的CPU时间。
  • 锁的不当使用: 长时间持有锁,特别是在执行耗时操作时,可能会导致其他线程长时间等待。
  • 线程数量过多: 当线程的数量远远超过处理器的数量,导致某些线程很少获得CPU时间。

解决方法:

使用公平锁(如`ReentrantLock`的公平模式),或者调整线程优先级,确保低优先级线程也能获得执行时间。

Java 示例

import java.util.concurrent.locks.ReentrantLock;

public class FairLockExample {
    private final ReentrantLock lock = new ReentrantLock(true); // Fair lock

    public void fairMethod() {
        lock.lock();
        try {
            // Critical section code
        } finally {
            lock.unlock();
        }
    }
}

4. 活锁(Livelock)

活锁是指线程虽然没有被阻塞,但也无法向前推进因为不断重复相同的操作,通常是因为线程间的相互响应。

场景:

  • 错误的失败恢复策略: 当线程尝试执行一个操作失败后,它会尝试重试相同的操作,而这个操作由于某些外部条件总是失败。
  • 过度响应: 当两个线程或更多线程设计为响应对方的动作时,它们可能会陷入一个循环,其中每个线程都在尝试避免与其他线程发生冲突。

解决方法:

引入随机性,例如在重试之前等待随机的时间,或者改变重试的策略。

Java 示例

public class LivelockExample {
    private boolean isActive;

    public synchronized void attemptAction() {
        while (isActive) {
            // 线程在这里尝试某个操作,但失败了
            try {
                Thread.sleep((long) (Math.random() * 100)); // 随机等待
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            // 一些其他的逻辑,可能会改变isActive的状态
        }
    }

    public synchronized void setActive(boolean active) {
        isActive = active;
    }
}

        在多线程编程时,始终要确保对共享资源的访问是适当同步的,同时要留意代码中可能导致死锁或活锁的设计。还应该避免对线程优先级的依赖,因为这可能会在不同的平台上导致不同的行为。

        在设计多线程程序时,理解这些问题及其出现的场景是非常重要的。这有助于程序员采取预防措施,比如使用适当的同步机制、设计合理的线程优先级和锁策略,以及实现健壮的错误处理和恢复策略。通过这些措施,可以大大减少多线程应用程序中出现问题的可能性。

有用请点赞,养成良好习惯!

疑问、交流、鼓励请留言!

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

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

相关文章

03.MySQL的体系架构

MySQL的体系架构 一、MySQL简介二、MySQL的体系架构三、MySQL的内存结构四、MySQL的文件结构 一、MySQL简介 MySQL是一个开源的关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,后被Sun公司收购,Sun公司被Oracle…

WEB渗透—PHP反序列化(九)

Web渗透—PHP反序列化 课程学习分享(课程非本人制作,仅提供学习分享) 靶场下载地址:GitHub - mcc0624/php_ser_Class: php反序列化靶场课程,基于课程制作的靶场 课程地址:PHP反序列化漏洞学习_哔哩…

《手把手教你》系列基础篇之4-python+ selenium自动化测试-xpath使用(详细教程)

1. 简介 俗话说:磨刀不误砍柴工,因此在我们要开始写自动化脚本之前,我们先来学习和了解几个基本概念,在完全掌握了这几个概念之后,有助于我们快速上手,如何去编写自动化测试脚本。 元素,在这个…

35KV配电室六氟化硫SF6设备泄漏监测方法

一、六氟化硫是什么? 六氟化硫又称为SF6,这种气体在常温常压下为无色无臭无毒的气体。不燃烧。对热稳定,没有腐蚀性,可以作为通用材料。电绝缘性能和消弧性能好,绝缘性能为空气的2~3倍,而且气体…

STM32CubeMX使用——Error: Flash Download failed - “Cortex-M7“

使用STM32CubeMX创建工程以后,工程正常编译,JTAG下载时会提示Error: Flash Download failed - “Cortex-M7” 但点击“确定”以后再次下载又不报错,此时进入debug模式,程序会直接停在while(1) 起初以为是STM32CubeMX没有配置好&…

mapboxgl 中给地图添加遮罩蒙版,并不遮罩其中一块区域

文章目录 概要效果预览技术思路技术细节小结 概要 本篇文章主要是给一整块地图添加遮罩层蒙版,但是不遮罩其中一个区域,以反向高亮地区内容。 效果预览 技术思路 这里要实现某个区域反显高亮,需要这个区域的边界json文件,与ech…

Kubernetes 学习总结(42)—— Kubernetes 之 pod 健康检查详解

Kubernetes 入门 回想 2017 年刚开始接触 Kubernetes 时,碰到 Pod一直起不来的情况,就开始抓瞎。后来渐渐地掌握了一些排查方法之后,这种情况才得以缓解。随着时间推移,又碰到了问题。有一天在部署某个 springboot 微服务时&…

C++初阶(十七)模板进阶

📘北尘_:个人主页 🌎个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上,不忘来时的初心 文章目录 一、非类型模板参数二、模板的特化1、概念2、函数模板特化3、类模板特化1、全特化2、偏特化 三…

【用unity实现100个游戏之19】制作一个3D传送门游戏,实现类似鬼打墙,迷宫,镜子,任意门效果

最终效果 文章目录 最终效果素材第一人称人物移动开门效果显示原理渲染相机跟着我们视角移动门的摄像机跟着我们旋转近裁剪面设置传送配置代码实现传送效果结束完结素材 https://assetstore.unity.com/packages/3d/props/interior/door-free-pack-aferar-148411

关于“Python”的核心知识点整理大全47

目录 16.1.10 错误检查 highs_lows.py highs_lows.py 16.2 制作世界人口地图:JSON 格式 16.2.1 下载世界人口数据 16.2.2 提取相关的数据 population_data.json world_population.py 16.2.3 将字符串转换为数字值 world_population.py 2world_population…

GIT如何重新生成ssh密钥过程

GIT如何重新生成ssh密钥过程 一、生成密钥前需要把之前的密钥删除吆 第一步:重新配置用户名和邮箱( Git Bash 或命令窗口) 1、配置用户命令:git config --global user.name “xxxxx” 2、配置邮箱命令:git config …

【OpenAI Q* 超越人类的自主系统】DQN :Q-Learning + 深度神经网络

深度 Q 网络:用深度神经网络,来近似Q函数 强化学习介绍离散场景,使用行为价值方法连续场景,使用概率分布方法实时反馈连续场景:使用概率分布 行为价值方法 DQN(深度 Q 网络) 深度神经网络 Q-L…

vue3-11

后端Java代码 src\router\a6router.ts文件 import { createRouter, createWebHashHistory } from vue-router import { useStorage } from vueuse/core import { Menu, Route } from ../model/Model8080 const clientRoutes [{path: /login,name: login,component: () > …

【基于VirtualBox及openEuler20.03 TLS SP1编译openGauss2.1.0源码】

【openEuler 20.03 TLS编译openGauss2.1.0源码】 一、安装环境二、安装步骤 一、安装环境 项目Value虚拟机virtualbox操作系统openEuler 20.03 TLSopenGauss2.1.0openGauss-third_party2.1.0 二、安装步骤 以下操作需要在root用户下执行 编辑/etc/selinux/config vim /etc/s…

《深入理解C++11:C++11新特性解析与应用》笔记四

第四章 新手易学,老兵易用 4.1 右尖括号>的改进 在 C98 中,有一条需要程序员规避的规则:如果在实例化模板的时候出现了连续的两个右尖括号 >,那么它们之间需要一个空格来进行分隔,以避免发生编译时的错误。C98 会将>&g…

uni-app condition启动模式配置

锋哥原创的uni-app视频教程: 2023版uniapp从入门到上天视频教程(Java后端无废话版),火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版),火爆更新中...共计23条视频,包括:第1讲 uni…

【Python】python 截取特定字符串前面的内容

Python截取特定字符串前面的内容 简介 本文将教会初学者如何使用Python来截取特定字符串前面的内容。Python提供了强大的字符串处理功能,可以轻松地实现这个需求。下面是整个流程的步骤: 在截取特定字符串前面的内容之前,我们首先需要找到要截取的特定内容的位置。我们可以使…

PHP的Laravel的数据库迁移

1.默认迁移文件 2.数据库迁移 在终端输入以下代码 php artisan migrate 我的报错啦!!!!! 数据库里面只有两张表,实际上应该有四张的!!! 解决方法: 反正表已…

ASUS华硕ROG幻16 2023款GU603VU VV VI笔记本电脑原厂Win11.22H2系统

链接:https://pan.baidu.com/s/1AgevUZleCHBJgCBcIp5CFQ?pwdhjxy 提取码:hjxy 华硕笔记本2023款幻16原厂Windows11系统自带所有驱动、出厂主题壁纸、Office办公软件、MyASUS华硕电脑管家、Armoury Crate奥创控制中心等预装程序 文件格式&#xff1…

【日志系列】什么是分布式日志系统?

✔️什么是分布式日志系统? 现在,很多应用都是集群部署的,一次请求会因为负载均衡而被路由到不同的服务器上面,这就导致一个应用的日志会分散在不同的服务器上面。 当我们要向通过日志做数据分析,问题排查的时候&#…