一网打尽!synchronized关键字入门(一)

简介: 一网打尽!synchronized关键字入门(一)

1.1 多线程一定快吗?


有人做过这样一个实验:“一段代码,有两个方法对各自的属性进行累加操作,其中一个方法采用多线程”,部分结果如下:

1.png


我们可以明显的看到,多线程不一定比单线程快


1.2 上下文切换


单核处理器也支持多线程执行代码:


通过给线程分配时间片来实现这个机制。


时间片一般是几十毫秒,所以CPU需要通过不停地切换线程来执行。当前执行完一个时间片后会切换下一个任务。在切换前会保存当前任务的状态,可以恢复这个任务之前的状态。 任务从保存到再次被加载的过程就是一次上下文切换。


时间片:操作系统分配给每个正在运行的进程(线程)微观上的一段CPU时间



测试上下文切换:


当我们一直运行多线程程序时,发现CS飙升到1000以上。

2.png


1.3 Java内存模型


在深入学习synchronized关键字之前,有必要先了解一下Java的内存模型


Java Memory Model(JMM):


Java线程之间的通信由JMM来控制,其决定一个线程对共享变量的写入,何时对另外一个线程可见。

3.png


为了提高效率,线程之间的共享变量是存储在主存当中,每一个线程都有一个属于自己的本地内存。


如果线程A与线程B之间要通信,需要经历下面两步:


1 线程A把本地内存中更新过的共享变量,刷新到主存中。


2 线程B到主存中重新读取更新后的共享变量。


1.4 主存与工作内存间的数据交互过程


4.png


lock     :作用于主存的变量,把一个变量标识为线程独占状态

unlock :作用于主存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

read    :作用于主存变量,它把一个变量的值从主存传输到线程的工作内存中,以便随后的load动作使用

load     :作用于工作内存的变量,它把read操作从主存中变量放入工作内存中

use      :作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用的变量的值,就会使用到这个指令

assign :作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中

store    :作用于主存中的变量,它把一个从工作内存中一个变量的值传送到主存中,以便后续的write使用

write    :作用于主存中的变量,它把store操作从工作内存中得到的变量的值放入主存的变量中

JMM对这八种指令制定了如下规则:


不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write

不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存

不允许一个线程将没有assign的数据从工作内存同步回主内存

一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作

一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁

如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值

如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量

对一个变量进行unlock操作之前,必须把此变量同步回主内存


2.1 多线程带来的可见性问题


可见性:一个线程对主存的修改可以及时被其他线程观察到。


5.png


上图,线程一把flag属性读取到线程私有的本地内存中,值为false;线程二把flag属性修改为true,并且刷新到主内存当中,但是线程一不知道flag被修改了。


解决方案:如果有加同步的机制,则会有lock、unlock操作,lock操作会使本地内存中的属性失效,从而去主内存中重新读取数据。



2.2 多线程带来的原子性问题


原子性:同一个时刻只能有一个线程来对它进行操作。


 如果使用五个线程同时对变量 i 进行1000次 ++ 操作,最后的结果并不一定等于5000。


 反编译结果可以看出:

6.png


index ++ 一共涉及到4条指令;


假设线程一执行到步骤三时CPU切换线程。线程二执行步骤一,这时index的值还是等于0,因为线程一并没有执行步骤四就被切换上下文了。 等线程二执行完成,又切回到线程一,线程一会接着执行步骤四,并不会重新获取index的值,导致计算结果不正确。



当加上了synchronized同步机制之后, 会插入monitorenter、monitorexit两条指令。


7.png


若线程一执行到步骤三,被切换到线程二,线程二执行monitorenter指令时会发现,这个对象已经被其他线程占用了,所以只能等待。


当又切回到线程一时,线程一操作完整个步骤执行monitorexit来释放锁。此时线程二才可以获得锁。 这样就能保证原子性。


2.3 多线程带来的有序性问题


有序性:Java在编译时和运行时会对代码进行优化,会导致程序最终的执行顺序与编写的顺序不同。


一个典型的例子就是JVM中的类加载:

8.png


类从加载到JVM到卸载一共会经历五个阶段:加载、连接、初始化、使用、卸载。这五个过程的执行顺序是一定的,但是在连接阶段,也会分为三个过程,即验证、准备、解析阶段,这三个阶段的执行顺序不是确定的,通常交叉进行,在一个阶段的执行过程中会激活另一个阶段。


解决方案:加锁。


2.4 多线程带来的活跃性问题


活跃性问题关注的是:某件事情是否会发生。


典型的就是死锁问题:如果一组线程中的每个线程都在等待一个事件的发生,而这个事件只能由该组中正在等待的线程触发,这种情况会导致死锁。


2.4.1 死锁的4个必要条件


造成死锁的原因有四个,破坏其中一个即可破坏死锁


互斥条件:在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程释放。

请求和保持条件:进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持占有。

不剥夺条件:进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

循环等待:在发生死锁时,必然存在一个进程对应的环形链。


2.5 性能问题


文章开头就提到过,在多线程中有一个非常重要的性能因素就是上下文切换。线程间的切换会涉及到一下几个步骤:

9.png


将CPU从一个线程切换到另一线程涉及挂起当前线程,保存其状态,例如寄存器,然后恢复到要切换的线程的状态,加载新的程序计数器。


2.5.1 引起线程切换的几种方式


当前正在执行的任务完成,系统的CPU正常调度下一个需要运行的线程

当前正在执行的任务遇到I/O等阻塞操作,线程调度器挂起此任务,继续调度下一个任务。

多个任务并发抢占锁资源,当前任务没有获得锁资源,被线程调度器挂起,继续调度下一个任务。

用户的代码挂起当前任务,比如线程执行sleep方法,让出CPU。

使用硬件中断的方式引起

 


相关文章
|
1天前
|
数据采集 人工智能 自然语言处理
3分钟采集134篇AI文章!深度解析如何通过云无影AgentBay实现25倍并发 + LlamaIndex智能推荐
结合阿里云无影 AgentBay 云端并发采集与 LlamaIndex 智能分析,3分钟高效抓取134篇 AI Agent 文章,实现 AI 推荐、智能问答与知识沉淀,打造从数据获取到价值提炼的完整闭环。
277 90
|
9天前
|
机器人 API 调度
基于 DMS Dify+Notebook+Airflow 实现 Agent 的一站式开发
本文提出“DMS Dify + Notebook + Airflow”三位一体架构,解决 Dify 在代码执行与定时调度上的局限。通过 Notebook 扩展 Python 环境,Airflow实现任务调度,构建可扩展、可运维的企业级智能 Agent 系统,提升大模型应用的工程化能力。
|
人工智能 前端开发 API
前端接入通义千问(Qwen)API:5 分钟实现你的 AI 问答助手
本文介绍如何在5分钟内通过前端接入通义千问(Qwen)API,快速打造一个AI问答助手。涵盖API配置、界面设计、流式响应、历史管理、错误重试等核心功能,并提供安全与性能优化建议,助你轻松集成智能对话能力到前端应用中。
715 154
|
15天前
|
人工智能 数据可视化 Java
Spring AI Alibaba、Dify、LangGraph 与 LangChain 综合对比分析报告
本报告对比Spring AI Alibaba、Dify、LangGraph与LangChain四大AI开发框架,涵盖架构、性能、生态及适用场景。数据截至2025年10月,基于公开资料分析,实际发展可能随技术演进调整。
967 152
|
2天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
1天前
|
数据采集 人工智能 搜索推荐
别再“调教”ChatGPT了!用Qwen2.5打造24小时在线数字分身
在AI时代,专属“数字分身”正从科幻走向现实。依托Qwen2.5-14B大模型、LoRA微调技术及LLaMA-Factory Online平台,仅需四步即可打造会说话、懂风格、能办事的个性化AI助手,让每个人拥有自己的“贾维斯”。
199 152