博客
关于我
Synchronize和Volatile底层实现原理
阅读量:357 次
发布时间:2019-03-04

本文共 2168 字,大约阅读时间需要 7 分钟。

最近在看《并发编程的艺术》这本书,希望能加深对并发领域的理解。书中第二章重点介绍了Java并发机制的底层实现原理,特别是volatile、synchronized以及原子操作等关键机制。本文将围绕这些内容进行详细记录。

1. 上下文切换

在单核或多核处理器中,多线程执行的本质是通过时间片轮-robin机制来实现的。每个线程都能获得一定的CPU时间段来执行任务。当一个任务完成自己的时间片后,就会切换到下一个任务。但在切换前,系统会保存当前任务的状态,以便切换后能够恢复到正确的上下文。

这种状态保存与恢复的过程被称为上下文切换。需要注意的是,上下文切换并非百分之百免费。创建线程、切换线程状态等操作都需要一定的开销,甚至在某些情况下,线程切换比单线程执行还要慢。这也说明并发编程并不是简单的快与慢的问题。

减少上下文切换的方法

为了减少上下文切换的开销,可以采用以下策略:

  • 无锁并发编程:通过将任务分成独立的段处理,每个线程负责特定的数据段。这种方法可以避免锁竞争带来的线程切换开销。

  • 使用CAS算法:Java的Atomic包中的CAS操作可以在不加锁的情况下进行原子性更新,减少线程切换的开销。

  • 优化线程数量:避免过度创建线程。特别是当任务量稀少时,过多的线程可能会导致大部分线程处于等待状态。

  • 协程:协程是一种在单线程内通过调度实现多任务并行的方式,能够在不引入线程切换的前提下实现并发。

  • 2. volatile关键字

    volatile关键字在Java中具有特殊的内存模型特性。任何访问volatile变量的线程都能看到该变量的最新值。这是因为volatile变量的写操作会触发缓存一致性机制,确保所有线程能够看到一致的值。

    volatile的实现原理

    当一个volatile变量进行写操作时,JVM会在生成的机器指令中插入Lock前缀指令。这个指令的作用是:

  • 写回内存:将处理器缓存中的数据写回系统内存。

  • 缓存锁定:使用缓存一致性机制,确保其他处理器在读取该内存地址时会发现缓存无效,从而必须重新从内存读取最新数据。

  • 这种机制保证了volatile变量的可见性和一致性,避免了多线程竞读或写入带来的数据不一致问题。

    3. synchronized的实现原理

    synchronized在Java中通过Monitor对象实现方法和代码块的同步。具体来说:

    • 代码块同步:使用monitorentermonitorexit指令。monitorenter会在进入同步代码块时尝试获取Monitor对象的所有权,monitorexit则会在退出时释放Monitor对象的所有权。

    • 方法同步:在方法执行和异常处插入monitorentermonitorexit指令,确保方法执行时的同步性。

    JVM会为每个对象分配一个Monitor对象。当一个线程尝试进入同步代码块时,会请求Monitor的所有权。如果Monitor已经被持有,JVM会等待当前持有Monitor的线程释放锁,才能继续执行。

    3.1 Java对象头

    synchronized锁是存在于Java对象头中的。Java对象头由以下三部分组成:

  • Mark Word:用于标记对象的状态,包括是否为活性对象、是否为偏向锁等信息。

  • 指向类的指针:指向类的Class对象,用于垃圾回收等场景。

  • 数组长度:对于数组对象,存储数组的长度。

  • 在深入理解synchronized机制之前,了解对象头的结构是非常重要的。

    3.2 锁的升级与对比

    在Java SE 1.6中,锁被进一步优化为四种状态:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。这些状态会根据竞争情况自动升级。

    偏向锁

    偏向锁是为减少锁的获取和释放代价而引入的。在大多数情况下,锁的竞争非常少,甚至可能只在同一个线程之间进行。偏向锁通过在栈帧中存储偏向锁的线程ID来减少锁的获取和释放开销。

    轻量级锁

    轻量级锁在竞争激烈时会升级为重量级锁。轻量级锁的加锁和解锁是通过循环CAS实现的。具体来说:

    • 加锁:尝试使用CAS将Mark Word替换为锁记录的指针。如果成功,线程获得锁;如果失败,线程会自旋直到成功。

    • 解锁:尝试将锁记录的指针替换回Mark Word。如果成功,锁被释放;如果失败,锁会膨胀为重量级锁。

    锁的优缺点

    锁的实现机制虽然高效,但也有其局限性。重量级锁的获取和释放开销较大,且锁竞争会导致线程等待。轻量级锁虽然减少了锁的获取和释放开销,但在竞争激烈时会升级为重量级锁,增加了调度开销。

    4. 原子操作的实现原理

    原子操作是保证多个操作原子性完成的关键机制。在处理器层面,原子操作主要通过总线锁和缓存锁实现。

    处理器层面的实现

  • 总线锁:通过LOCK#信号确保在总线上独占内存访问。

  • 缓存锁:在缓存一致性机制的帮助下,确保缓存操作的原子性。

  • Java中的原子操作可以通过循环CAS实现。CAS操作虽然简单,但也面临着ABA问题、自旋开销大以及只能操作单个变量等挑战。

    Java如何实现原子操作

    对于多个共享变量的原子操作,Java通常会使用锁机制。对于单个共享变量,JVM可以通过循环CAS实现原子操作。这种实现方式既保证了原子性,又尽量减少了锁的使用。

    参考

    本文内容主要参考自《Java并发编程的艺术》。

    转载地址:http://xgdr.baihongyu.com/

    你可能感兴趣的文章
    NO 157 去掉禅道访问地址中的zentao
    查看>>
    no available service ‘default‘ found, please make sure registry config corre seata
    查看>>
    No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
    查看>>
    no connection could be made because the target machine actively refused it.问题解决
    查看>>
    No Datastore Session bound to thread, and configuration does not allow creation of non-transactional
    查看>>
    No fallbackFactory instance of type class com.ruoyi---SpringCloud Alibaba_若依微服务框架改造---工作笔记005
    查看>>
    No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalanc
    查看>>
    No mapping found for HTTP request with URI [/...] in DispatcherServlet with name ...的解决方法
    查看>>
    No mapping found for HTTP request with URI [/logout.do] in DispatcherServlet with name 'springmvc'
    查看>>
    No module named 'crispy_forms'等使用pycharm开发
    查看>>
    No module named cv2
    查看>>
    No module named tensorboard.main在安装tensorboardX的时候遇到的问题
    查看>>
    No module named ‘MySQLdb‘错误解决No module named ‘MySQLdb‘错误解决
    查看>>
    No new migrations found. Your system is up-to-date.
    查看>>
    No qualifying bean of type XXX found for dependency XXX.
    查看>>
    No qualifying bean of type ‘com.netflix.discovery.AbstractDiscoveryClientOptionalArgs<?>‘ available
    查看>>
    No resource identifier found for attribute 'srcCompat' in package的解决办法
    查看>>
    no session found for current thread
    查看>>
    No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android
    查看>>
    NO.23 ZenTaoPHP目录结构
    查看>>