• volatile与CAS


    volatile与CAS

    volatile

    作用:(面试常考 必须记住)

    1.保障线程可见性

    线程运行过程如上图所示 先访问 然后吧这个值copy一份到自己的工作空间,然后再去对这个值进行改变,但检查这个方法有无新值不容易控制,加入了volatile在之后保证了线程的可见性 当main主线程对m方法值进行更改之后 t1就会马上看到

    2.禁止指令重排序

    指令重排序是和cpu有关系的 每次写都会被线程读到,加了volatile之后,cpu原来执行一体哦啊指令的时候是一步步执行,但是现在cpu为了提高效率,它会把指令并发的来执行,第一个指令执行得到一半的时候第二个就可能已经开始执行了,这叫流水线式执行。

    这是new一个方法的过程图

    如果没有volatile cpu可能就会对1 2 3 步重排序 可能在杠申请内存给a赋初始值0 的时候就把a调走了

    所以给它加了volatile之后就不会出现指令重排序的可能。

    CAS(无锁优化 自旋)

    假如我原先想改变某一个值0 ,我想把它变成1,但是其中我想做到线程安全,就只能加锁 synchronized,不然线程就不安全。我们现在可以用另一个操作来代替这把锁,就是cas操作,可以把它想象成一个方法,这个方法有三个参数,cas(V,Expected,New Value)。

    V第一个参数就是要改的那个值;Expected第二个参数是期望当前的这个值会是及;NewValue是要设定的新值。比如原来这个值变成3了,我这个线程想改这个值的时候我一定期望你现在是3,是3我才改的,如果你在我改的过程变成了4了,那你跟我的期望值就对不上了,说明有另一个线程改了这个值,那我这个CAS就重新再试一下,再试的时候我希望这个值是4,在修改的时候期望值就是4,没有其他的线程修改这个值,那好,我概念改成5,这就是CAS操作。

    ABA问题(面试)

    假如是你有一个值,我拿到这个值是1,想把它变成2 ,我拿到1用cas操作,期望值是1,准备变成2,这个对象Object。早这个过程种,没有一个线程改过的话我肯定是可以更改的,但是如果有一个线程把这个1变成2后来又变成了1.中间值发生过更改,它不会影响我这个cas下面的操作,这就是ABA问题。

    怎么解决:

    如果是int类型的,最终值是你所期望值,没有关系,这种没有关系可以不去管这个问题;如果确实想管这个问题 可以加版本号,做任何一个值的修改,修改完之后加1,后面检查的时候连带版本号一块都检查。

    总结:如果是基础类型,无所谓,不会影响结果值;

    ​ 如果是引用类型:就像你的女朋友和你分手后又复合,中间经历了其他的男人;(通俗易懂)

    第三节 Atomic类和线程同步新机制

    CountDownLatch

    latch意思是门栓 ,这个锁的意思就是给线程加了给门栓 (倒数的一个门栓5,4,3,2,1,计数完了,门栓打开程序继续往下执行。

    CycicBarrier

    CycicBarrier是一个同步工具 意思是循环栅栏,假如两个线程 一个定义了100个参数线程 在主线程调用的时候我给它加上这么一个栅栏 满20人 栅栏就倒了 到了就把数据放出去 然后栅栏再立起来 以此类推 知道100个参数全出去。就像坐车一样 100个人坐车 但车只有20座位 上来20 线程一看满20了 好 发车 然后再来 再满20 好 发车,这样运行五次就100个人全走了。

    Phaser

    Phaser就是一个分阶段的栅栏 更像是结合了CountDownLatch和CycicBarrier

    ReadWriteLock(重点)

    意思很明显 字面意思 读 写 就是叫读写锁

    读写锁的概念其实就是共享锁和排他锁,读锁就是共享锁,写锁就是排他锁。

    就好比学校的组织结构 有多个人同时访问学校网址这个组织结构 有读的 有写的 加入A同学想往里面写个名字 叫王八摔 但是刚写到王八 数据就被B同学读走了 所以为了避免这种情况我们就要加锁

    这种锁new ReentranReadWriteLocl()是ReadWriteLock的一种实现,在这给实现里我们又分出两把锁来 一个是readLock,另一个是WriteLock,通过它的方法readWriteLock.readLock()来拿到readLok对象,读锁我们就拿到了。通过readWriteLock.writeLock()拿到write对象。这两把锁在我读的时候扔进去,因此,读线程是可以一起读的,也就是说所有的读线程可以一秒完成。

    总结:加了这个读写锁意思就是允许其他读线程一起读 ,写线程来了我不给它写,你先别写,等我读完了你再写。读线程读的时候我们一起读 ,因为读是不改变线程原来的内容,写线程上来就把整个线程全锁定,你先不要读,等我写完你在读。

    Semaphore

    简单含义就是限流

    Semaphore s = new Semaphore() 是来控制几个线程同时执行的 售票处 你不管再多的人来买票 我售票窗口就三个 只能允许三个线程同时运行。

    acquire();这个方法是阻塞方法 acquire的意思就是得到 如果Semaphore s = new Semaphore(5)写的是5 那我acquire一下之后它就得减一变成4 后面的线程此时如果同时执行 访问到的就是四 以此类推 直到变成0 就是五个线程同时运行了 别的线程就等着等到下一批五个 五个 。。。

    线程结束的时候必须要加个 release();方法 因为我刚acquire完 减一 如果线程完成后不加回来 那么后面线程就没办法运行了 ,所以必须要加release 还原化。

    Semaphore s = new Semaphore(1,true)第二个值穿true是设置公平锁,但这基本用不到 因为用到这个就是能控制线程的先来后到 这个不容易控制 所以说这个公平锁意义不大。

    Exchanger

    这个就是扩展知识面用的 简单说就是一个交换器 就是把两个线程里面的数据交换一下

    这个使用场景比较多的应该就是游戏里面双方互换装备 。

  • 相关阅读:
    HDU 2852 KiKi's K-Number (主席树)
    HDU 2089 不要62
    Light oj 1140 How Many Zeroes?
    Bless You Autocorrect!
    HDU 6201 transaction transaction transaction
    HDU1561 The more ,The better (树形背包Dp)
    CodeForces 607B zuma
    POJ 1651 Mulitiplication Puzzle
    CSUOJ 1952 合并石子
    Uva 1599 Ideal path
  • 原文地址:https://www.cnblogs.com/beizhai/p/13796265.html
Copyright © 2020-2023  润新知