专业的编程技术博客社区

网站首页 > 博客文章 正文

浅谈并发与多线程(并发和多线程的关系)

baijin 2024-10-07 06:18:41 博客文章 4 ℃ 0 评论

平常我们经常提到的并发,多线程,线程不安全,那为什么会产生并发多线程不安全的原因的,这个需要从操作硬件到JVM的内存模型来说起:

1、操作硬件,因为CPU和其它设备,如内存、IO间的反应速度差的不是几个档次了,CPU的计算速度远远大于内存、IO的读写速度,所以在硬件中会加下高速缓存cache来作为内存与CPU间的中间层,提高CPU计算时取结果的速度。

CPU==>高速cache=>[一致性协议】

CPU==>高速cache=>[一致性协议】==》主内存

这种使用模式就是有一个问题,就是cpu计算线程每次都是在cache中计算完后才会刷到主内存中,jvm的内存模型也是采用该方式,优点是可以屏蔽各个操作系统的cpu计算和内存读写的不同点,形成统一的模式,开发者不需要考试编写的多线程代码会在不同操作系统中产生不一样的效果。

2、JVM的内存模型操作顺序:

线程=》工作内存=》【store,write原子协议】=》主内存

在这个过程由于多线程都拥有各自私有的工作内存,这就是涉及到从主内存拷贝变量值到工作内存,也涉及到工作内存操作完后需要刷新变量值到主内存,这是分步的操作,在多线程竞争操作的情况下,就有可能会产生工作内存与主内存同步延迟的情况,而延迟的发生就是导致我们常说的线程不安全的问题。

3、JVM如何解决线程不安全问题

那如何解决线程不安全的问题呢,jvm提供了各个手段,从常识来讲,我们可以想下,如何解决同步延迟的问题:

1)可以在线程操作时直接刷新主内存,读时也强制从主内存进行刷新读取,对应的java解决方式是提供volatile关键时,它的出现是保证了有线程修改了变量的值会直接反应到主内存中,读取也从主内存强制刷新读取,保证了多个线程的可见性,但可见性不一定保证是线程安全的。

举个例子,A和B合作玩一个取球放到桶里的游戏,球在对面,C是裁判,在桶旁边负责对桶里的数量进行报数(相当直接刷新主内存)。

游戏开始,刚开始桶里的球为0个,裁判C告诉A和B,桶的球为0(可见性),然后A和B同时出发,因为有A和B的速度不一样,A率先拿到球然后放回桶里,裁判C报数桶有一球,但由于B之前得到的信息是0,所以B拿球回来以为桶只有一个,实际算上他的已经是两个了(这涉及到原子性的问题,读和算是分步操作)。

假设又来了一个D要玩,裁判C会跟D说现在有两球,因为A、B都各自入了一个,对D来说桶的数量是可见的而且是正确的,不存在裁判C还没算出结果。

2)sychronized同步锁,以monitorenter和monitorexit指令进行代码块监控,保持单一线程执行及退出,当然也可以用lock锁

3)final关键字,保证变量不可变也是线程安全的一种方式

4)还有jdk提供的并发工具包里面具有原子类的类java.util.concurrent包下的 atomic类

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表