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

news2024/9/22 10:08:08

文章目录

    • 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外卖订购系统
  • 【数据结构学习】从零起步:学习数据结构的完整路径

在这里插入图片描述

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

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

相关文章

正规文法、正规式、确定的有穷自动机DFA、不确定的有穷自动机NFA 的概念、区分以及等价性转换【我直接拿下!】

文章目录 正规文法正规式有穷自动机确定的有穷自动机——DFA不确定的有穷自动机——NFADFA 与 NFA 的区分 正规式转换为正规文法正规文法转换为正规式NFA 转换为 DFANFA 最小化 NFA 转换为正规式正规式转换为 NFA正规文法转换为 NFANFA 转换为正规文法 前言&#xff1a; 在学习…

C语言--程序环境和预处理(宏)

目录 前言 本章重点&#xff1a; 1. 程序的翻译环境和执行环境 2. 详解编译链接 2.1 翻译环境​编辑 2.2 编译本身也分为几个阶段 2.3 运行环境 3. 预处理详解 3.1 预定义符号 3.2 #define 3.2.1 #define 定义标识符 3.2.2 #define 定义宏 2.2.3 #define 替换规则 …

fetch网络请求详解

一&#xff1a;三种常见的网络请求对比&#xff1a; AJAX&#xff1a;基于XMLHttpRequest收发请求&#xff0c;使用较为繁琐&#xff0c;代码量会比较多axios&#xff1a;基于promise的请求客户端&#xff0c;在浏览器和node中均可使用&#xff0c;使用便捷&#xff0c;功能强…

系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第五部分:支付系统

本心、输入输出、结果 文章目录 系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第五部分&#xff1a;支付系统前言如何学习支付系统信用卡为什么被称为“银行最赚钱的产品”&#xff1f;VISA/万事达卡如何赚钱&#xff1f;步骤说明为什么开证行应该得到补偿 当我们在商家…

Linux中的开发工具(yum,vim,gcc/g++,gdb,Makefile,git)

文章目录 1. Linux软件包管理器——yumyum 语法yum 常用命令安装 yum 仓库源 2. Linux编辑器——vimvim 的五种常用模式模式切换vim 基本操作命令模式命令集&#xff08;1&#xff09;光标命令&#xff08;2&#xff09;复制粘贴命令&#xff08;3&#xff09;撤销与重做&#…

深度学习---卷积神经网络

卷积神经网络概述 卷积神经网络是深度学习在计算机视觉领域的突破性成果。在计算机视觉领域。往往输入的图像都很大&#xff0c;使用全连接网络的话&#xff0c;计算的代价较高。另外图像也很难保留原有的特征&#xff0c;导致图像处理的准确率不高。 卷积神经网络&#xff0…

安全多方计算框架最全合集(持续更新)

安全多方计算框架 本文对现有安全多方计算/学习框架进行了全面、系统的梳理。 目前大部分安全多方计算框架主要基于秘密共享、同态加密、混淆电路以及相关基本模块的组合。通常使用定制的协议来支持特定数量的参与方&#xff08;一般为两方或三方&#xff09;&#xff0c;导致…

我发现用StarUML来画UML也挺香的

2023年10月22日&#xff0c;周日晚上 我已经决定以后都用StarUML来画UML了&#xff0c;因为这个软件不仅免费&#xff0c;而且太适合画UML图了 我之前主要用plantUML和draw.io来画UML&#xff0c; plantUML虽然是通过文本来生成UML图&#xff0c;但是排版不是不好看&#xff…

“智能文件批量改名工具:轻松管理文件名,一键去除特殊符号“

你是否曾经在面对一堆文件名中包含特殊符号&#xff0c;而感到困扰&#xff0c;不知道如何快速、准确地处理它们&#xff1f;现在&#xff0c;我们为你带来了一款智能文件批量改名工具&#xff0c;它可以轻松地帮助你去除文件名中的特殊符号&#xff0c;让你的文件管理更加规范…

【试题002】C语言有关于sizeof的使用

1.说明&#xff1a;sizeof()是测量数据类型所占用的内存字节数&#xff0c;字符串常量在存储时除了要存储有效字节外&#xff0c;还要存储一个字符串结束志‘\0’。 2.代码举栗子&#xff1a; #include <stdio.h> int main() {char str[] "book";printf(&qu…

网络协议--Traceroute程序

8.1 引言 由Van Jacobson编写的Traceroute程序是一个能更深入探索TCP/IP协议的方便可用的工具。尽管不能保证从源端发往目的端的两份连续的IP数据报具有相同的路由&#xff0c;但是大多数情况下是这样的。Traceroute程序可以让我们看到IP数据报从一台主机传到另一台主机所经过…

开源LLEMMA发布:超越未公开的顶尖模型,可直接应用于工具和定理证明

深度学习自然语言处理 原创作者&#xff1a;Winnie 今天向大家介绍一个新的开源大语言模型——LLEMMA&#xff0c;这是一个专为数学研究而设计的前沿语言模型。 LLEMMA解数学题的一个示例 LLEMMA的诞生源于在Proof-Pile-2数据集上对Code Llama模型的深度训练。这个数据集是一个…

Java 8 新特性 Ⅱ

方法引用 举例: Integer :: compare 理解: 可以看作是基于lambda表达式的进一步简化 当需要提供一个函数式接口的实例时, 可以使用lambda表达式提供实例 当满足一定条件下, 可以使用方法引用or构造器引用替换lambda表达式 实质: 方法引用作为函数式接口的实例 (注: 需要熟悉…

【AOA-VMD-LSTM分类故障诊断】基于阿基米德算法AOA优化变分模态分解VMD的长短期记忆网络LSTM分类算法(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

人大金仓获评“2023年度软件和信息技术服务名牌企业”

近日&#xff0c;中国电子信息行业联合会在2023世界数字经济大会暨第十三届智慧城市与智能经济博览会上&#xff0c;发布了“2023年度软件和信息技术服务名牌企业”&#xff0c;凭借在企业规模、技术创新、市场影响力等方面的突出表现&#xff0c;人大金仓成功入选。 此次评选在…

计组03:20min导图复习 中央处理器

&#x1f433;前言 图源&#xff1a;文心一言 考研笔记整理&#xff0c;纯复习向&#xff0c;思维导图基本就是全部内容了&#xff0c;不会涉及较深的知识点~~&#x1f95d;&#x1f95d; 第1版&#xff1a;查资料、画思维导图~&#x1f9e9;&#x1f9e9; 编辑&#xff1a;…

【数值分析】2 - 插值法

文章目录 一、引言1.1 插值法引入1.2 常用插值法1.3 插值法定义 二、插值法研究的问题2.1 插值多项式存在的唯一性2.2 如何构造n次多项式2.2.1 待定系数法2.2.2 拉格朗日插值法2.2.2.1 拉格朗日多项式2.2.2.2 拉格朗日插值余项2.2.2.3 例题2.2.2.4 拉格朗日插值法的问题 2.2.3 …

【大疆智图】大疆智图(DJI Terra 3.0.0)安装及使用教程

大疆智图是一款以二维正射影像与三维模型重建为主的软件,同时提供二维多光谱重建、激光雷达点云处理、精细化巡检等功能。它能够将无人机采集的数据可视化,实时生成高精度、高质量三维模型,满足事故现场、工程监测、电力巡线等场景的展示与精确测量需求。 文章目录 1. 安装D…

shell学习脚本04(小滴课堂)

他就可以直接读出来了。不需要在sh后面加参数。 可以用-s隐藏内容&#xff1a; 可以用-t进行指定几秒后显示。 -n限制内容长度。 输入到长度为5自动打印。 我们把-s放到-p后面的话&#xff1a; 这样会出错。 如果最后加5m会一直闪烁。 大家可以按照需求自行使用。

42907-2023 硅锭、硅块和硅片中非平衡载流子复合寿命的测试 非接触涡流感应法

1 范围 本文件描述了用非接触式涡流感应法测试太阳能电池用单晶硅锭、硅块和硅片中非平衡载流子复 合寿命的方法。 本文件适用于非平衡载流子复合寿命在0.1μs&#xff5e;10000 μs、电阻率在0.1 Ω cm&#xff5e;10000 Ω cm 的硅锭、硅块和硅片的测试。其中瞬态光电导衰…