Java并发

article/2025/7/22 12:04:01

一、进程和线程
 

进程:

程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态系统运行一个程序即是一个进程从创建,运行到消亡的过程

在Java中,当我们启动main函数时其实就是启动了一个JVM进程,而main函数所在的线程就是这个进程中的一个线程,也称主线程

线程:

线程是比进程更小的执行单位。一个进程执行过程中可以产生多个线程。

与进程不同的是同类的多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器、虚拟机栈和本地方法栈,因此系统在产生/切换线程时代价比进程小得多-----线程也成为轻量级进程。

线程与进程的关系、区别和优缺点:

一个进程中可以有多个线程,多个线程共享进程的方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器虚拟机栈 和 本地方法栈

线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响线程执行开销小,但不利于资源的管理和保护;而进程正相反。

程序计数器、虚拟机栈和本地方法栈私有原因:

程序计数器:

程序计数器功能:①字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制--------顺序执行、选择、循环等    ②多线程情况下,程序计数器用于记录当前线程执行的位置,当线程切换时能够继续该线程原操作。

Java程序执行流程:

编写源代码文件(.java后缀)---> Java编译器编译源代码转为字节码(.class后缀)---> Java虚拟机(JVM)加载.class文件中的字节码  ---> 字节码解释器解释字节码并执行 + JIT编辑器在运行时将热点代码编译为机器代码提高性能  ---> 执行程序 (JVM执行字节码或机器代码,管理内存、线程等)---> 运行时管理(JVM负责内存分配、垃圾回收)

程序计数器参与部分:

  • JVM 加载字节码时,程序计数器会为每个线程分配一个独立的计数器
  • 执行字节码的过程中,程序计数器指向当前正在执行的字节码指令的地址。
  • 每当一条指令执行完成后,程序计数器会更新,指向下一条要执行的指令。
  • 方法被调用时,程序计数器保存当前指令的位置,以便在方法返回时能够继续执行。
  • 这对于支持多线程和方法调用非常重要,确保线程之间的独立执行顺序。

(当一个方法被调用时,程序计数器会保存调用该方法时的下一条指令的位置。这意味着在方法执行完成后,可以返回到正确的位置继续执行)    

程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。    

虚拟机栈和本地方法栈:

虚拟机栈功能: 

每个 Java 方法在执行之前会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。

本地方法栈功能

与虚拟机栈相似------虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机使用到的本地(Native)方法服务

Native方法

是Java 程序中声明的,可以在底层使用其他语言(如 C 或 C++)实现的功能,通常用于访问系统资源或提高性能。

虚拟机栈和本地方法栈私有是为了保证线程中的局部变量不被别的线程访问到

二、线程创建

线程创建方式:

①继承Thread类  

每个线程都是一个 Thread 实例,调用 start() 方法后会执行 run() 方法。系统为每个线程分配资源和调度。

class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}
}// 使用
MyThread thread = new MyThread();
thread.start();

②实现Runnable接口  

创建一个 Runnable 对象,并将其传递给 Thread。调用 start() 时,线程会执行 Runnable 的 run() 方法,线程与任务分离,便于复用。

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}
}// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();

 

③Callable接口  

与 Runnable 类似,但 Callable 可以返回结果并抛出异常使用 FutureTask 来管理线程的结果和状态。

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<String> {@Overridepublic String call() {return "Callable is running";}
}// 使用
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
Thread thread = new Thread(futureTask);
thread.start();

④使用线程池  

线程池重用线程,减少创建和销毁线程的开销。线程由 ExecutorService 管理,可以通过提交任务来控制线程的执行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(() -> System.out.println("Task is running in thread pool"));
executorService.shutdown();

 

⑤CompletableFuture类

基于 Future 和 Executor,支持异步编程和链式调用。它实现了非阻塞的方式来处理并发任务,允许更灵活的组合和错误处理。

import java.util.concurrent.CompletableFuture;CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println("CompletableFuture is running");
});
future.join(); // 等待任务完成

非阻塞:在当前线程下创建线程池(默认ForkJoinPool)来执行异步任务

线程生命周期:

线程在生命周期中会伴随代码执行而在不同状态间切换(区别于Bean的周期):

  • NEW: 初始状态,线程被创建出来但没有被调用 start()
  • RUNNABLE: 运行状态,线程被调用了 start()等待运行的状态。
  • BLOCKED:阻塞状态,锁被其它线程占有,需要等待锁释放。
  • WAITING:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
  • TIME_WAITING:超时等待状态,相当于在等待状态的基础上增加了超时限制,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
  • TERMINATED:终止状态,执行完run()方法之后进入该状态,表示该线程已经运行完毕。

RUNNABLE中细分了两个状态:

①RUNNING :可运行状态的线程获得了 CPU 时间片后就处于 RUNNING(运行) 状态

②READY : 线程在调用 start() 方法后开始运行,线程这时候处于 READY(可运行) 状态

二合一原因:两种状态切换太快,没有必要区分

多线程:

并发与并行的区别:

并发:两个及两个以上的作业在同一时间段内执行。

并行:两个及两个以上的作业在同一时刻执行。

同步和异步的区别:

同步:发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。

异步:调用在发出之后,不用等待返回结果,该调用直接返回


线程调度方式:

①抢占式调度(JVM默认):

操作系统决定何时暂停当前正在运行的线程,并切换到另一个线程执行。

这种切换通常是由系统时钟中断(时间片轮转)或其他高优先级事件(如 I/O 操作完成)触发的。

存在上下文切换开销,但公平性和 CPU 资源利用率较好,不易阻塞。

②协同式调度:

线程执行完毕后,主动通知系统切换到另一个线程。

可以减少上下文切换带来的性能开销,但公平性较差,容易阻塞。

单核CPU支持多线程问题:

单核 CPU 是支持 Java 多线程的。操作系统通过时间片轮转的方式,将 CPU 的时间分配给不同的线程。尽管单核 CPU 一次只能执行一个任务,但通过快速在多个线程之间切换,可以让用户感觉多个任务是同时进行的。

单核CPU运行多线程效率问题:

情况一:

线程为IO密集型----IO 密集型的线程主要进行输入输出操作,如读写文件、网络通信等,需要等待 IO 设备的响应,而不占用太多的 CPU 资源。

效率会提高----如果线程是 IO 密集型的,那么多个线程同时运行可以利用 CPU 在等待 IO 时的空闲时间,提高了效率。

情况二:

线程为CPU密集型----CPU 密集型的线程主要进行计算和逻辑处理,需要占用大量的 CPU 资源。

效率降低----如果线程是 CPU 密集型的,那么多个线程同时运行会导致频繁的线程切换,增加了系统的开销,降低了效率。

线程死锁:

死锁:

多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态

预防死锁:

死锁的产生的必要条件:

互斥条件:该资源任意一个时刻只由一个线程占用。

请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。

循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

预防-----破坏上述必要条件

乐观锁和悲观锁:

悲观锁:

悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放

悲观锁思想的实现:synchronized和ReentrantLock等独占锁

乐观锁:

乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制CAS 算法)。

版本号机制:

每个数据项都有一个版本号,表示数据的状态。

在进行更新时,线程会检查当前版本号与预期版本号(即操作开始时的版本号)是否一致。

如果一致,则更新数据并增加版本号;如果不一致,则表示数据已被其他线程修改,更新操作失败。

Compare-And-Swap(CAS)算法:

CAS 是一个原子操作,包括三个参数:要更新的变量值(Var)、预期值(E)和新值(N)。

CAS 检查内存地址 V 的当前值是否等于预期值 E,如果是,则将其更新为新值 N。

CAS 操作要么成功(更新),要么失败(不更新),并返回当前值。


http://www.hkcw.cn/article/xYGIbkJZBq.shtml

相关文章

通过回调函数注册定时器触发事件

1、说明 使用回调函数&#xff0c;注册定时器触发事件的模式&#xff0c;提高定时器中断的可操作性&#xff0c;那如何实现呢&#xff1f; 2、.h文件 下面是定时器句柄的声明 3、.c文件 3.1、静态定时器句柄头 3.2、定时器回调函数处理 下面的函数是放在1ms的中断中的&#…

Visual Studio+SQL Server数据挖掘

这里写自定义目录标题 工具准备安装Visual studio 2017安装SQL Server安装SQL Server Management Studio安装analysis service SSMS连接sql serverVisual studio新建项目数据源数据源视图挖掘结构部署模型设置挖掘预测 部署易错点 工具准备 Visual studio 2017 analysis servi…

大模型-attention汇总解析之-MHA

一、MHA(Multi-Head Attention) 1.1 MHA 原理 MHA&#xff08;Multi-Head Attention&#xff09;称为多头注意力&#xff0c;开山之作所提出的一种 Attention 计算形式&#xff0c;它是当前主流 LLM 的基础工作。在数学原理上&#xff0c;多头注意力 MHA 等价于多个独立的单头…

历年上海交通大学计算机保研上机真题

2025上海交通大学计算机保研上机真题 2024上海交通大学计算机保研上机真题 2023上海交通大学计算机保研上机真题 在线测评链接&#xff1a;https://pgcode.cn/school String Match 题目描述 Finding all occurrences of a pattern in a text is a problem that arises freq…

DeepSeek-R1-0528-Qwen3-8B 本地ollama离线运行使用和llamafactory lora微调

参考: https://huggingface.co/deepseek-ai/DeepSeek-R1-0528-Qwen3-8B 量化版本: https://huggingface.co/unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF https://docs.unsloth.ai/basics/deepseek-r1-0528-how-to-run-locally 1、ollama运行 升级ollama版本到0.9.0 支持直接…

数字人革新教育:开启智慧教学新时代

随着人工智能技术的迅猛发展&#xff0c;数字人正在逐步走进教育领域&#xff0c;成为传统教学模式的颠覆者。广州深声科技有限公司&#xff08;以下简称“深声科技”&#xff09;凭借其在智能语音、数字人及多模态交互等核心技术上的深厚积累&#xff0c;推出了一系列创新性产…

Linux操作系统之进程(四):命令行参数与环境变量

目录 前言&#xff1a; 什么是命令行参数 什么是环境变量 认识环境变量 PATH环境变量 HOME USER OLDPWD 本地变量 本地变量与环境变量的差异 核心要点回顾 结语&#xff1a; 前言&#xff1a; 大家好&#xff0c;今天给大家带来的是一个非常简单&#xff0c;但也十…

IDA dumpdex经典脚本(记录)

一个dumpdex的IDA插件 毕业了,暂时用不着了,存起来 import idaapi import structdef dumpdex(start, len, target):rawdex idaapi.dbg_read_memory(start, len)fd open(target, wb)fd.write(rawdex)fd.close()def getdexlen(start):pos start 0x20mem idaapi.dbg_read_mem…

第2期:APM32微控制器键盘PCB设计实战教程

第2期&#xff1a;APM32微控制器键盘PCB设计实战教程 一、APM32小系统介绍 使用apm32键盘小系统开源工程操作 APM32是一款与STM32兼容的微控制器&#xff0c;可以直接替代STM32进行使用。本教程基于之前开源的APM32小系统&#xff0c;链接将放在录播评论区中供大家参考。 1…

Redis的安装与使用

网址&#xff1a;Spring Data Redis 安装包&#xff1a;Releases tporadowski/redis GitHub 解压后 在安装目录中打开cmd 打开服务&#xff08;注意&#xff1a;每次客户端连接都有先打开服务&#xff01;&#xff01;&#xff01;&#xff09; 按ctrlC退出服务 客户端连接…

Redis 难懂命令-- ZINTERSTORE

**背景&#xff1a;**学习的过程中 常用的redis命令都能快速通过官方文档理解 但是还是有一些比较难懂的命令 **目的&#xff1a;**写博客记录一下&#xff08;当然也可以使用AI搜索&#xff09; 在Redis中&#xff0c;ZINTERSTORE 是一个用于计算多个有序集合&#xff08;So…

7.atlas安装

1.服务器规划 软件版本参考&#xff1a; https://cloud.google.com/dataproc/docs/concepts/versioning/dataproc-release-2.2?hlzh-cn 由于hive3.1.3不完全支持jdk8,所以将hive的版本调整成4.0.1。这个版本没有验证过&#xff0c;需要读者自己抉择。 所有的软件都安装再/op…

RabbitMQ和MQTT区别与应用

RabbitMQ与MQTT深度解析&#xff1a;协议、代理、差异与应用场景 I. 引言 消息队列与物联网通信的重要性 在现代分布式系统和物联网&#xff08;IoT&#xff09;生态中&#xff0c;高效、可靠的通信机制是构建稳健、可扩展应用的核心。消息队列&#xff08;Message Queues&am…

【技能篇】RabbitMQ消息中间件面试专题

1. RabbitMQ 中的 broker 是指什么&#xff1f;cluster 又是指什么&#xff1f; 2. 什么是元数据&#xff1f;元数据分为哪些类型&#xff1f;包括哪些内容&#xff1f;与 cluster 相关的元数据有哪些&#xff1f;元数据是如何保存的&#xff1f;元数据在 cluster 中是如何分布…

[3D GISMesh]三角网格模型中的孔洞修补算法

&#x1f4d0; 三维网格模型空洞修复技术详解 三维网格模型在扫描、重建或传输过程中常因遮挡、噪声或数据丢失产生空洞&#xff08;即边界非闭合区域&#xff09;&#xff0c;影响模型的完整性与可用性。空洞修复&#xff08;Hole Filling&#xff09;是计算机图形学和几何处…

基于Spring Boot+Vue 网上书城管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

[ctfshow web入门] web81

信息收集 新增过滤:&#xff0c;伪协议都有:&#xff0c;这意味着伪协议不能用了 if(isset($_GET[file])){$file $_GET[file];$file str_replace("php", "???", $file);$file str_replace("data", "???", $file);$file st…

2025年应用心理学与社会环境国际会议(ICAPSE 2025)

2025年应用心理学与社会环境国际会议&#xff08;ICAPSE 2025&#xff09; 2025 International Conference on Applied Psychology and Social Environment 一、大会信息 会议简称&#xff1a;ICAPSE 2025 大会地点&#xff1a;中国北京 审稿通知&#xff1a;投稿后2-3日内通…

Windows 11 家庭版 安装Docker教程

Windows 家庭版需要通过脚本手动安装 Hyper-V 一、前置检查 1、查看系统 快捷键【winR】&#xff0c;输入“control” 【控制面板】—>【系统和安全】—>【系统】 2、确认虚拟化 【任务管理器】—【性能】 二、安装Hyper-V 1、创建并运行安装脚本 在桌面新建一个 .…

Redis 数据恢复的月光宝盒,闪回到任意指定时间

在数据库的运维工作中&#xff0c;DBA 应该选择哪一种方案&#xff0c;确保 Redis 数据库崩溃后可以对数据进行回档&#xff0c;恢复业务运行&#xff1f; 一般情况下&#xff0c;DBA 可以通过 Redis 原生的持久化机制&#xff0c;如 RDB 快照持久化或者 AOF 日志持久化的方案…