美文网首页并发编程
AtomicInteger实现原理

AtomicInteger实现原理

作者: cbhe | 来源:发表于2020-04-19 18:05 被阅读0次

    概要

    1.实现锁的一般思想是什么?

    在“不同”中找“相同“。分布式情况下,机器不同但数据库相同,则用数据库实现锁。单机多线程情况下,内存相同,则使用内存实现锁。

    2.AtomicInteger中维护的value值为何要用volatile关键字修饰?

    确保直接读取和直接为value设置值时操作的是内存中的值而不是缓存中的值,因为volatile有禁用缓存的作用。

    3.AtomicInteger为何可以实现多线程下的准确计数?

    因为AtomicInteger提供的increamentAndGet或其他相关方法,底层是使用操作系统的cmpxchg来实现的而不是以往的三步:load -> add -> store

    详细讲解

        无论是单机多核心还是多机分布式系统,想要实现同步(或者说是加锁解锁)就要在“不同”中寻找“相同”,在“隔离”中找“联系”,找到不变量。比如在多机分布式系统的场景下,程序跑在不同的机器上,有不同的cpu、内存、硬盘,但如果共用一个mysql数据库,则可以利用这个数据库来实现分布式锁,通过对某个表中的某一行的update操作的成功与否,就可以确定某个机器上的某个线程是否加锁成功。在单机多核心多线程的场景下,线程可能运行在不同的cpu上使用不同的缓存资源,但这台机器的内存就是我们要寻找的不变量,通过对一个内存单元的存取操作,来实现锁,从而实现线程同步和互斥。Java语言的volatile就是根据这一原理来设计的。

    volatile关键字在java语言中有两个重要的语义:

    1.禁止指令重排序

    在编译器对字节码进行优化的时候,在volatile之前的语句禁止放到volatile的后面,后面的也一样不能放到volatile前面。volatile相当于内存屏障。

    2.禁用缓存

    对volatile修饰的变量的读操作,就是直接读取的内存中的值,而不是缓存的值。对volatile修饰的变量的写操作也会直接写入内存。

    AtomicInteger被设计出来用于进行多线程计数操作的场景,因此,它并不能被称之为“线程安全的Integer”,因为它并不能在除此之外的其他场景下替代Integer。比如进行乘除运算。

    我们知道,简单的计数方法就是每次对一个变量进行加一操作。而对于一个线程来说,这个加一操作一般情况下在字节码层面上是要分成三步去完成的:获取当前值,加一,写回。因此如果多个线程对一个变量进行操作时往往会出现一个线程加一完了还没写回,另一个线程又取出原值进行加一的尴尬情况,造成计数不准确的问题。

    而AtomicInteger就是利用了操作系统的一个叫做cmpxchg的指令替代了之前的三步指令,实现了原子操作,这样加一操作就不会有不准确的问题了。而AtomicInteger中维护的value要用volatile修饰,则是因为要确保在直接设置和读取value时,操作的是内存中的值。

    相关文章

      网友评论

        本文标题:AtomicInteger实现原理

        本文链接:https://www.haomeiwen.com/subject/tobvbhtx.html