高薪程序员必修课-java并发编程的bug源头
前言
Java并发编程虽然强大,但也容易引发复杂的bug。并发编程的bug主要源自以下几个方面:竞态条件、死锁、内存可见性问题和线程饥饿。了解这些bug的源头及其原理,可以帮助开发者避免和解决这些问题。以下是详细的讲解和相应的示例。
1. 竞态条件(Race Condition)
原理
竞态条件发生在多个线程同时访问和修改共享资源时,由于操作的交错顺序不同,导致程序的行为和结果不可预测。具体表现为多个线程在没有适当同步的情况下访问和修改同一变量。
示例
下面是一个竞态条件的示例,演示多个线程同时修改共享变量 counter 的问题。
public class RaceConditionExample {private static int counter = 0;public static void main(String[] args) {Runnable task = () -> {for (int i = 0; i < 1000; i++) {counter++;}};Thread thread1 = new Thread(task);Thread thread2 = new Thread(task);thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final counter value: " + counter); // 预期结果应为2000}
}
2. 死锁(Deadlock)
原理
死锁是指两个或多个线程相互等待对方持有的资源,导致所有线程都无法继续执行。死锁通常发生在多线程程序中使用多个锁时,锁获取的顺序不一致导致循环等待。
示例
下面是一个简单的死锁示例,两个线程尝试获取相同的锁,但顺序不同,导致死锁。
public class DeadlockExample {private static final Object lock1 = new Object();private static final Object lock2 = new Object();public static void main(String[] args) {Thread thread1 = new Thread(() -> {synchronized (lock1) {System.out.println("Thread 1: Holding lock 1...");try { Thread.sleep(100); } catch (InterruptedException e) {}System.out.println("Thread 1: Waiting for lock 2...");synchronized (lock2) {System.out.println("Thread 1: Holding lock 1 & 2...");}}});Thread thread2 = new Thread(() -> {synchronized (lock2) {System.out.println("Thread 2: Holding lock 2...");try { Thread.sleep(100); } catch (InterruptedException e) {}System.out.println("Thread 2: Waiting for lock 1...");synchronized (lock1) {System.out.println("Thread 2: Holding lock 1 & 2...");}}});thread1.start();thread2.start();}
}
3. 内存可见性问题(Memory Visibility Issues)
原理
内存可见性问题指的是一个线程对共享变量的修改,另一个线程可能看不到。Java内存模型(JMM)允许线程将变量缓存到寄存器或CPU缓存中,而不是立即写入主内存。这会导致不同线程看到的变量值不一致。
示例
下面是一个内存可见性问题的示例,展示了一个线程对变量 running 的修改,另一个线程可能看不到。
public class MemoryVisibilityExample {private static boolean running = true;public static void main(String[] args) {Thread worker = new Thread(() -> {while (running) {// Busy-wait loop}System.out.println("Worker thread stopped.");});worker.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}running = false;System.out.println("Main thread set running to false.");}
}
4. 线程饥饿(Thread Starvation)
原理
线程饥饿发生在某些线程长期得不到执行机会,通常是因为高优先级线程不断占用CPU时间,低优先级线程无法获取CPU资源。导致某些线程长期处于等待状态。
示例
下面是一个线程饥饿的示例,展示了低优先级线程可能永远得不到执行机会。
public class ThreadStarvationExample {public static void main(String[] args) {Thread highPriorityThread = new Thread(() -> {while (true) {// High priority task}});highPriorityThread.setPriority(Thread.MAX_PRIORITY);Thread lowPriorityThread = new Thread(() -> {while (true) {System.out.println("Low priority thread running...");}});lowPriorityThread.setPriority(Thread.MIN_PRIORITY);highPriorityThread.start();lowPriorityThread.start();}
}
总结
竞态条件
- 原理:多个线程同时访问和修改共享资源。
- 示例:多个线程同时增加共享变量。
死锁
- 原理:两个或多个线程相互等待对方持有的资源。
- 示例:线程1持有锁1等待锁2,线程2持有锁2等待锁1。
内存可见性问题
- 原理:一个线程对共享变量的修改,另一个线程可能看不到。
- 示例:一个线程修改变量
running,另一个线程看不到变化。
线程饥饿
- 原理:某些线程长期得不到执行机会。
- 示例:高优先级线程不断占用CPU时间,低优先级线程无法获取CPU资源。
理解并发编程中的这些bug源头和原理,并采用适当的同步机制(如 synchronized、Lock、volatile)以及并发工具(如 CountDownLatch、Semaphore、ConcurrentHashMap),可以有效避免和解决这些问题。
相关文章:
高薪程序员必修课-java并发编程的bug源头
前言 Java并发编程虽然强大,但也容易引发复杂的bug。并发编程的bug主要源自以下几个方面:竞态条件、死锁、内存可见性问题和线程饥饿。了解这些bug的源头及其原理,可以帮助开发者避免和解决这些问题。以下是详细的讲解和相应的示例。 1. 竞态…...
c++:#include 某文件.h底层如何寻找其.cpp实现
在C中,当你编写了一个头文件(如MyLibrary.h)和对应的实现文件(如MyLibrary.cpp)时,其他源文件(如main.cpp)只需要包含头文件(#include "MyLibrary.h"ÿ…...
uniapp中如何进行微信小程序的分包
思路:在uniapp中对微信小程序进行分包,和原生微信小程序进行分包的操作基本上没区别,主要就是在pages.json中进行配置。 如图,我新增了一个包diver-page 此时需要在pages.json中的subPackages数组中新增一项 root代表这个包的根…...
win10下安装PLSQL14连接Oracle数据库
问题背景 在使用Oracle开发过程中,经常会使用工具来连接数据库,方便查询、处理数据。其中有很多工具可以使用,比如dbeaver、plsql等。本文主要介绍在win10环境下,plsql14的安装步骤以及安装过程中遇到的一些问题。 安装步骤及问题…...
高考失利咨询复读,银河补习班客服开挂回复
补习班的客服在高考成绩出来后,需要用专业的知识和足够的耐心来回复各种咨询,聊天宝快捷回复软件,帮助客服开挂回复。 前言 高考成绩出来,几家欢喜几家愁,对于高考失利的学生和家长,找一个靠谱的复读补…...
java 代码块
Java中的代码块主要有三种类型:普通代码块、静态代码块、构造代码块。它们的用途和执行时机各不相同。 普通代码块:在方法内部定义,使用一对大括号{}包围的代码片段。它的作用域限定在大括号内,每当程序执行到该代码块时就会执行其…...
vue中避免多次请求字典接口
vuex缓存所有字典项 背景vuex管理所有字典项调用字典接口处理字典项数据的filter页面中使用字典 背景 每次用到字典都需要通过对应的字典type调用一次字典接口,当一个页面用到字典项很多时,接口请求炒鸡多,会导致接口响应超时。 本篇文章改为…...
Snappy使用
Snappy使用 Snappy是谷歌开源的压缩和解压的开发包,目标在于实现高速的压缩而不是最大的压缩 项目地址:GitHub - google/snappy:快速压缩器/解压缩器 Cmake版本升级 该项目需要比较新的cmake,CMake 3.16.3 or higher is requi…...
跨越重洋:在Heroku上配置Pip镜像源的终极指南
🌐 跨越重洋:在Heroku上配置Pip镜像源的终极指南 Heroku是一个支持多种编程语言的云平台即服务(PaaS),它允许开发者部署和管理应用程序。然而,由于Heroku的服务器位于海外,直接使用Python的包管…...
SpringBoot + 虚拟线程,性能炸裂!
一、什么是虚拟线程 虚拟线程是Java19开始增加的一个特性,和Golang的携程类似,一个其它语言早就提供的、且如此实用且好用的功能,作为一个Java开发者,早就已经望眼欲穿了。 二、虚拟线程和普通线程的区别 “虚拟”线程…...
Java Character类
Character是char的包装类 转义序列 Character类的方法...
Python中的爬虫实战:猫眼电影爬虫
随着互联网技术的快速发展,网络上的信息量越来越庞大。猫眼电影作为国内领先的电影数据平台,为用户提供了全面的电影信息服务。本文将介绍如何利用python编写简单的猫眼电影爬虫,获取电影相关数据。 爬虫概述 爬虫,即网络爬虫&a…...
WAIC2024 | 华院计算邀您共赴2024年世界人工智能大会,见证未来科技革新
在智能时代的浪潮汹涌澎湃之际,算法已成为推动社会进步的核心力量。作为中国认知智能技术的领军企业,华院计算在人工智能的广阔天地中,不断探索、创新,致力于将算法的潜力发挥到极致。在过去的时日里,华院计算不断探索…...
数据库原理之数据库基本概念
目录 前言 基本概念 数据库完整性 前言 今天我们来看看数据库的基本概念,帮助大家对数据库有一点点最基本的了解 基本概念 4个基本概念 数据data:描述事物的符号,数据库中存储的基本对象。 数据库Database:长期存储在计算机…...
vue2项目的打包以及部署
打包 当我们写好vue2的项目后,可以通过npm build来对项目进行打包 npm build 打包完成后我们可以看到在当面目录下生成了dis目录,src下的文件都会被打包进这个目录里,当然打包后的文件我们不能直接在浏览器打开,需要进行部署 部署 1.新建一个…...
Java的全局异常处理代码
第一步:先写一个异常管理类: package com.example.firefighting.exceptions;import com.example.firefighting.utils.Result; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerA…...
Hi3861 OpenHarmony嵌入式应用入门--LiteOS semaphore作为锁
CMSIS 2.0 接口中的 Semaphore(信号量)是用于嵌入式系统中多线程或中断服务例程(ISR)之间同步和共享资源保护的重要机制。Semaphore 是一种用于控制对多个共享资源访问的同步机制。它可以被看作是一个计数器,用于跟踪可…...
注意!年龄越大,社交圈子越窄?其实这是老人的理性选择!数学家告诉你:何时该跳槽,何时该坚守!你必须知道的三个智慧:让你的人生更加精彩!
我们到底应该在什么情况下探索新事物,什么情况下专注于已有的东西呢?本质上来说,这个问题就是在询问,你究竟应该耗费精力去探索新的信息,还是专注从既有的信息中获取收获? 有人采访了临终的老人,…...
[SwiftUI 开发] 嵌套的ObservedObject中的更改不会更新UI
1. 发生问题的demo 业务逻辑代码 class Address: ObservableObject {Published var street "123 Apple Street"Published var city "Cupertino" }class User: ObservableObject {Published var name "Tim Cook"Published var address Addr…...
全面了解机器学习
目录 一、基本认识 1. 介绍 2. 机器学习位置 二、机器学习的类型 1. 监督学习 2. 无监督学习 3. 强化学习 三、机器学习术语 1. 训练样本 2. 训练 3. 特征 4. 目标 5. 损失函数 四、机器学习流程 五、机器学习算法 1. 分类算法 2. 聚类算法 3. 关联分析 4. …...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
