java并发编程学习笔记(2):Volatile、synchronized、原子操作

本文深入解析并发编程核心概念,涵盖Volatile关键字、synchronized机制、锁的升级策略及原子操作实现,助您掌握多线程编程关键技巧。

并发编程的重要术语

术语名称英文解释
CASCompare And Swap(比较并交换)CAS操作需要输入两个数值,旧值和新值。在操作期间先看旧值有无变化,若没变化,才交换成新值。若旧值变了,则不交换
原子性一个或多个操作,要么都成功,要么都失败。中间不能由于任何原因中断。
举例:给人转账有两个操作,一是自己的钱减少,二是对方的钱变多,转账这个过程就要求是原子性的。

原子性

可见性

有序性(顺序性)

Volatile关键字

(1)Volatile关键字的工作原理

  1. 将当前处理器缓存行的数据写回到系统内存。
  2. 个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。
    即当一个变量被 volatile 修饰时,任何线程对它的写操作都会立即刷新到主内存中(而不是Cache),并且会强制让缓存了该变量的线程中的数据清空,必须从主内存重新读取最新数据。
    注:

(2)Volatile的作用

  1. 如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。
  2. volatile 修饰之后并不是让线程直接从主内存中获取数据,依然需要将变量拷贝到工作内存(Cache)中。
  3. volatile 并不能保证线程安全性。

(3)Volatile的特点

  1. 可见性
    对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
  2. 原子性
    对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。

synchronized的定义与实现原理

1.synchronized关键字的三种用法

(1)修饰普通同步方法

  • 锁是当前实例对象
    进入同步代码快之前要获得当前对象实例的锁。

(2)修饰静态同步方法

  • 锁是当前类的Class对象
    会作用于类的所有对象实例。(因为静态成员不属于任何一个实例对象,是类成员(如static表明这个成员是该类的一个静态资源,不管new了多少对象,static是公用的,只有一份))。

注:
因此,若线程A调用一个实例对象的非静态synchronized方法,而线程B需要调用这个实例对象所属类的静态synchronized方法,是不会发生排斥现象。

(3)修饰同步代码块

  • 锁是synchronized括号里配置的对象
    进入同步代码前要获得给定对象的锁。

2.synchronized关键字的底层实现原理(JVM)

进入同步代码时需要获得锁,在退出或抛出异常时释放锁。
(1)同步代码块的底层实现

  • monitorenter
    编译后插入到同步代码块的开始位置。
  • monitorexit
    插入到方法结束处和异常处。
  • 实现过程
    执行monitorenter指令,线程视图获取锁(即moniter,存在与对象头中。当计数器为0则可以获取(获取后计数器为1))。执行moniterexit指令后,释放锁(计数器置为0)。

(2)同步方法的底层实现

  • ACC_SYNCHRONIZED
    该标识指明了该方法是一个同步方法。

volatile和Synchronixed的比较

原子性(线程安全问题)可见性重排序
volatile不保证保证禁止
Synchronixed保证保证允许

锁的升级与对比

  • 升级目的
    为了减少获得锁和释放锁带来的性能消耗。

  • 锁主要存在四中状态
    无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争的激烈而逐渐升级。(锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率)

  • 三种锁的对比

优点缺点适用场景
偏向锁加锁和解锁不需要额外的消耗若线程间存在竞争,会带来额外的锁撤销的消耗只有一个线程访问同步块的场景
轻量级锁竞争的线程不会阻塞若始终得不到锁竞争的线程,使用自旋会消耗cpu追求响应时间,同步块执行速度非常快
重量级锁线程竞争不使用自旋,不会消耗cpu线程阻塞,响应时间缓慢追求吞吐量,同步块执行速度较长

1.偏向锁

(1)作用
在很多应用场景中,大部分对象生命周期中最多会被一个线程锁定,使用偏斜锁可以降低无竞争开销

(2)偏向锁加锁
在一个线程获取锁时,会在对象头的Mark Word部分记录线程ID。(表示这个对象偏向于当前线程,所以并不涉及真正的互斥锁)。以后该线程在加解锁时,只需要简单的测一下MarkWord中的ID即可。

2.轻量级锁

java实现原子操作

通过锁和循环CAS的方式来实现。

1.CAS(比较和交换)

CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做(通过调用JNI的代码实现的)

2.CAS实现原子操作的三大问题

  1. ABA问题
    执行CAS时,若V从A→B→A。CAS会认为V没变化,实际上V变化了。(解决办法,追加版本号,每次V变化的时候版本号+1)

  2. 循环时间长开销大
    自旋CAS若长时间不成功,会给CPU带来巨大开销。

  3. 只能保证一个共享变量的原子操作
    对多个共享变量操作,循环CAS不能保证操作的原子性,此时可以使用锁。(锁机制保证只有获得锁的线程才能操作锁定的内存区域)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值