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

深入理解多线程编程和 JVM 内存模型

文章目录

    • 1. 理解进程和线程的概念
      • 进程(Process)
      • 线程(Thread)
    • 2. 理解竞态条件和死锁
      • 竞态条件(Race Condition)
      • 死锁(Deadlock)
    • 3. JVM 内存模型
      • 堆(Heap)
      • 栈(Stack)
      • 方法区(Method Area)
      • 本地方法栈(Native Method Stack)
      • PC 寄存器(Program Counter Register)
      • 垃圾回收
    • 4. 常见的多线程编程模式
      • 生产者-消费者模式
      • 线程池模式
      • 并发集合
    • 结论

在这里插入图片描述

🎉欢迎来到Java面试技巧专栏~深入理解多线程编程和 JVM 内存模型


  • ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹
  • ✨博客主页:IT·陈寒的博客
  • 🎈该系列文章专栏:Java面试技巧
  • 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习
  • 🍹文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️

在现代软件开发中,多线程编程已经成为不可或缺的一部分。多线程使得我们可以更好地利用多核处理器,提高应用程序的性能。但多线程编程也伴随着一系列挑战,如竞态条件(race condition)和死锁。本文将探讨多线程编程的基本概念,JVM 内存模型,以及常见的多线程编程模式。

在这里插入图片描述

1. 理解进程和线程的概念

进程(Process)

进程是操作系统中的一个独立的执行单元,拥有自己的内存空间、文件描述符、以及系统资源。每个进程都运行在自己的独立地址空间中,互不干扰。进程之间的通信通常需要复杂的机制,如进程间通信(IPC)。

示例代码:

import os# 获取当前进程的 ID
print("当前进程 ID:", os.getpid())# 创建新进程
if os.fork() == 0:print("子进程 ID:", os.getpid())
else:print("父进程 ID:", os.getpid())

线程(Thread)

线程是进程中的执行单元,多个线程可以共享同一个进程的内存和资源。线程之间的通信相对容易,因为它们共享相同的地址空间。但也因为共享,线程之间需要特殊的同步机制来避免竞态条件等问题。

示例代码:

public class MyThread extends Thread {public void run() {System.out.println("线程执行");}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}

2. 理解竞态条件和死锁

竞态条件(Race Condition)

竞态条件指的是多个线程同时访问共享数据时,由于执行顺序不确定而导致的不确定行为。竞态条件可以导致程序出现不一致的结果,因此需要适当的同步机制来避免。

示例代码:

public class RaceConditionExample {private static int sharedCounter = 0;public static void main(String[] args) {Runnable incrementTask = () -> {for (int i = 0; i < 1000; i++) {sharedCounter++;}};Thread thread1 = new Thread(incrementTask);Thread thread2 = new Thread(incrementTask);thread1.start();thread2.start();try {thread1.join();thread2.join();System.out.println("共享计数器的值: " + sharedCounter);} catch (InterruptedException e) {e.printStackTrace();}}
}

死锁(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: 持有锁1...");try { Thread.sleep(100); } catch (InterruptedException e) {}System.out.println("Thread 1: 尝试获取锁2...");synchronized (lock2) {System.out.println("Thread 1: 获取到锁2...");}}});Thread thread2 = new Thread(() -> {synchronized (lock2) {System.out.println("Thread 2: 持有锁2...");try { Thread.sleep(100); } catch (InterruptedException e) {}System.out.println("Thread 2: 尝试获取锁1...");synchronized (lock1) {System.out.println("Thread 2: 获取到锁1...");}}});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

3. JVM 内存模型

JVM(Java Virtual Machine)内存模型定义了 Java 程序在内存中的数据存储和访问规则。JVM 内存模型将内存划分为不同的区域,如堆、栈、方法区等。

堆(Heap)

堆是用于存储对象实例的内存区域。所有通过 new 关键字创建的对象都存储在堆中。堆中的对象可以被多个线程共享。

栈(Stack)

栈是用于存储方法调用的内存区域。每个线程都拥有自己的栈,用于存储方法的局部变量和方法调用的信息。栈中的数据只能由所属线程访问。

方法区(Method Area)

方法区用于存储类信息、静态变量、常量池等数据。它也是多线程共享的区域。

本地方法栈(Native Method Stack)

本地方法栈用于执行本地方法,通常由 C 或 C++ 编写。本地方法栈中的数据只能由本地方法访问。

PC 寄存器(Program Counter Register)

PC 寄存器用于存储当前线程执行的字节码指令地址。它是线程私有的。

垃圾回收

JVM 负责自动进行垃圾回收,以释放不再使用的对象占用的内存。垃圾回收算法和策略对程序的性能和内存消耗有重要影响。

4. 常见的多线程编程模式

生产者-消费者模式

生产者-消费者模式是一种经典的多线程编程模式,用于解决生产者和消费者之间的协作问题。生产者线程生产数据并将其放入缓冲区,消费者线程从缓冲区中取出数据并进行处理。

示例代码:

import java.util.LinkedList;public class ProducerConsumerExample {private LinkedList<Integer> buffer = new LinkedList<>();private int capacity = 2;public void produce() throws InterruptedException {int value = 0;while (true) {synchronized (this) {while (buffer.size() == capacity) {wait();}System.out.println("生产者生产: " + value);buffer.add(value++);notify();Thread.sleep(1000);}}}public void consume() throws InterruptedException {while (true) {synchronized (this) {while (buffer.isEmpty()) {wait();}int value = buffer.poll();System.out.println("消费者消费: " + value);notify();Thread.sleep(1000);}}}public static void main(String[] args) {ProducerConsumerExample example = new ProducerConsumerExample();Thread producerThread = new Thread(() -> {try {example.produce();} catch (InterruptedException e) {e.printStackTrace();}});Thread consumerThread = new Thread(() -> {try {example.consume();} catch (InterruptedException e) {e.printStackTrace();}});producerThread.start();consumerThread.start();}
}

线程池模式

线程池模式是为了重用线程,减少线程的创建和销毁开销。线程池可以管理多个线程,并为它们分配任务。

示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);Runnable task1 = () -> {System.out.println("任务1执行");};Runnable task2 = () -> {System.out.println("任务2执行");};executor.submit(task1);executor.submit(task2);executor.shutdown();}
}

并发集合

Java 提供了一些并发集合类,如 ConcurrentHashMap 和 `

ConcurrentLinkedQueue`,用于在多线程环境中安全地操作集合数据。

示例代码:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class ConcurrentMapExample {public static void main(String[] args) {Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();concurrentMap.put("one", 1);concurrentMap.put("two", 2);int value = concurrentMap.get("one");System.out.println("Value: " + value);}
}

结论

多线程编程是现代软件开发的重要组成部分,但也伴随着一系列挑战。程序员需要深入理解多线程的概念、JVM 内存模型,以及常见的多线程编程模式,来编写安全和高效的多线程应用程序。同时,了解垃圾回收、线程池和并发集合等工具和技术也是提高多线程编程能力的关键。

在这里插入图片描述

希望本文的内容能帮助读者更好地理解多线程编程,提高在多线程环境下开发应用程序的能力。不同的应用场景和需求可能需要不同的多线程编程模式和技术,因此不断学习和实践是非常重要的。多线程编程是一个复杂而有趣的领域,也是软件开发的重要一部分。


🧸结尾 ❤️ 感谢您的支持和鼓励! 😊🙏
📜您可能感兴趣的内容:

  • 【Java面试技巧】Java面试八股文 - 掌握面试必备知识(目录篇)
  • 【Java学习路线】2023年完整版Java学习路线图
  • 【AIGC人工智能】Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么
  • 【Java实战项目】SpringBoot+SSM实战:打造高效便捷的企业级Java外卖订购系统
  • 【数据结构学习】从零起步:学习数据结构的完整路径

在这里插入图片描述

相关文章:

深入理解多线程编程和 JVM 内存模型

文章目录 1. 理解进程和线程的概念进程&#xff08;Process&#xff09;线程&#xff08;Thread&#xff09; 2. 理解竞态条件和死锁竞态条件&#xff08;Race Condition&#xff09;死锁&#xff08;Deadlock&#xff09; 3. JVM 内存模型堆&#xff08;Heap&#xff09;栈&am…...

QML(25)——文本输入框组件的区别(TextField TextInput TextArea TextEdit)

目录 效果展示适用场景文本组件TextLabelText和Label的区别 单行文本输入框TextFieldTextInputTextField 和 TextInput的区别 多行文本输入框TextAreaTextArea 和 TextEdit 的区别 效果展示 适用场景 场景组件属性短文本Text长文本 末尾省略Textelide: Text.ElideRight文本设置…...

SpringBoot连接MySQL密码错误,报错:Access denied for user

记&#xff1a;一次连接MySQL报密码错误&#xff0c;Access denied for user 检查步骤&#xff1a; 核对用户和密码是否正确&#xff0c;用工具登陆试下。如果配置文件是yml格式&#xff0c;配置密码是123456这种纯数字&#xff0c;记得加上单/双引号。检查云上数据库配置&am…...

如何使用visual studio 2010构建SQLite3.lib文件

sqlite3官网只提供了dll&#xff0c;并没有lib文件。需要自己生成sqlite3.lib。因项目升级到x64&#xff0c;以前并没有生成64位的链接库&#xff0c;需要自己创建。本人电脑操作系统windows 10, 开发环境为visual studio 2010。下面是详细生成过程。 1. 从源下载源&#xff08…...

反转链表review

反转链表 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; }* }*/ class …...

UG\NX二次开发 获取用户默认设置中的绘图信息 UF_PLOT_ask_session_job_options

文章作者:里海 来源网站:《里海NX二次开发3000例专栏》 感谢粉丝订阅 感谢 m0_58724732 订阅本专栏,非常感谢。 简介 UG\NX二次开发 获取用户默认设置中的绘图信息 UF_PLOT_ask_session_job_options 效果 代码 #include "me.hp...

数字图像处理实验记录五(图像的空间域增强-锐化处理)

前言&#xff1a; 文章目录 一、基础知识1&#xff0c;什么是锐化&#xff1f;2&#xff0c;为什么要锐化&#xff1f;3&#xff0c;怎么进行锐化&#xff1f; 二、实验要求任务1&#xff1a;任务2&#xff1a;任务3&#xff1a; 三、实验记录&#xff1a;任务1&#xff1a;任…...

基于水基湍流优化的BP神经网络(分类应用) - 附代码

基于水基湍流优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于水基湍流优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.水基湍流优化BP神经网络3.1 BP神经网络参数设置3.2 水基湍流算法应用 4.测试结果…...

0010【Edabit ★☆☆☆☆☆】Maximum Edge of a Triangle

【Edabit 算法 ★☆☆☆☆☆】Maximum Edge of a Triangle algorithms math numbers Instructions Create a function that finds the maximum range of a triangle’s third edge, where the side lengths are all integers. Examples nextEdge(8, 10) // 17 nextEdge(5, 7…...

Godot 官方2D C#重构(3):TileMap使用

文章目录 前言Godot Tilemap使用Tilemap使用TileSet和TilemapTilemap 图片资源添加TileSet&#xff0c;开始切图导入图片切图 简单添加TileMap如何使用 Auto Tilemap使用Auto Tilemap 前言 Godot 官方 教程 Godot 2d 官方案例C#重构 专栏 Godot 2d 重构 github地址 Godot Tilem…...

6.DApp-用Web3实现前端与智能合约的交互

题记 用Web3实现前端与智能合约的交互&#xff0c;以下是操作流程和代码。 准备ganache环境 文章地址&#xff1a;4.DApp-MetaMask怎么连接本地Ganache-CSDN博客 准备智能合约 文章地址&#xff1a; 2.DApp-编写和运行solidity智能合约-CSDN博客 编写index.html文件 <!…...

数据异常值检测

数据异常值检测 参考&#xff1a; 数据异常值的检测方法-基于Python 独家 | 每个数据科学家应该知道的五种检测异常值的方法&#xff08;附Python代码&#xff09; 异常检测主要方法总结 14种数据异常值检验的方法&#xff01; 14种数据异常值检验的方法 浅谈数据挖掘中的…...

监听redis键失效事件实现延迟功能

用Redis实现延迟队列&#xff0c;我研究了两种方案&#xff0c;发现并不简单 SpringBoot实现Redis失效监听事件—KeyExpirationEventMessageListener Redis 监听过期的key&#xff08;KeyExpirationEventMessageListener&#xff09; 项目背景 需求上说&#xff0c;需要延迟…...

使用UniApp实现视频数组自动下载与播放功能:一步步指导

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

C语言笔试面试必刷题

&#x1f38a;【面经】专题正在持续更新中&#xff0c;内含C语言&#xff0c;数据结构&#xff0c;Linux&#xff0c;网络编程等✨&#xff0c;欢迎大家前往订阅本专题&#xff0c;获取更多详细信息哦&#x1f38f;&#x1f38f;&#x1f38f; &#x1fa94;本系列专栏 - ​​…...

window11安装Python环境

python环境安装 访问Python官网:https://www.python.org/ 点击downloads按钮&#xff0c;在下拉框中选择系统类型(windows/Mac OS/Linux等) 选择下载最新版本的Python cmd命令如果出现版本号以及>>>则表示安装成功 如果出现命令行中输入python出现如下错误 可能…...

SpringBoot中的日志使用

SpringBoot的默认使用 观察SpringBoot的Maven依赖图 可以看出来&#xff0c;SpringBoot默认使用的日志系统是使用Slf4j作为门户&#xff0c;logback作为日志实现 编写一个测试代码看是否是这样 SpringBootTest class SpringbootLogDemoApplicationTests {//使用Slf4j来创建LOG…...

微信小程序中监听横屏竖屏

直接上代码 第一步&#xff1a;在你想要监听页面的json文件中添加此节点 "pageOrientation": "auto" 第二步&#xff1a;wx.onWindowResize() page&#xff08;{ onLoad() {this.kstd()},kstd(){ // 监听屏幕旋转事件 wx.onWindowResize((res)>{// …...

云原生概述

1. 何谓云原生 云原生是一种构建和运行应用程序的方法&#xff0c;是一套技术体系和方法论。云原生&#xff08;CloudNative&#xff09;是一个组合词&#xff0c;CloudNative。Cloud表示应用程序位于云中&#xff0c;而不是传统的数据中心&#xff1b;Native表示应用程序从设…...

消失的它:网络层分片包中的第一个分片包去哪了?

在网络层IP包分片的过程中&#xff0c;遇到了大麻烦&#xff01; 主机A&#xff1a; IP地址&#xff1a;192.168.0.10/24 MAC地址&#xff1a;02:00:00:00:00:10 主机B&#xff1a; IP地址&#xff1a;192.168.0.20/24 MAC地址&#xff1a;02:00:00:00:00:20 MTU&#xff1a;1…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...