Java并发编程(四)- 资源分配(互斥)

目录

资源分配(互斥)

不变模式

      享元模式

写时复制模式 Copy-on-Write

线程本地存储模式 - ThreadLocal

CAS和原子类

      原子化的基本数据类型

      原子化的对象引用类型

      原子化数组

      原子化对象属性更新器

      原子化的累加器


资源分配(互斥)

        资源分配(互斥)主要指保证同一时刻只允许一个/部分线程访问共享资源;

        解决资源分配(互斥)问题的方案:

               1, 管程(Synchronized,并发包中的Lock),通过加互斥锁,将共享变量及其对共享

                变量的操作统一封装起来。保证同一时刻,只有一个/部分的线程能访问共享资源。

                2,无锁方案;  

                        不变模式;

                        写时复制模式Copy-on-Write;

                        线程本地存储模式ThreadLocal;

                        CAS和原子类;

        管程内容详见: 协作篇章中管程模块;

        无锁方案相对于互斥锁方案,性能更好,基本不会出现死锁问题;但是在自旋很多次时,可

        能会出现饥饿和活锁问题。

        

不变模式

        解决并发问题,最简单的办法就是让共享变量只有读操作,而没有写操作。

        不变性,就是对象一旦被创建之后,状态就不再发生变化。

        将一个类所有的属性都设置成 final 的,并且只允许存在只读方法,那么这个类基本上就具备

不可变性了。更严格的做法是这个类本身也是 final 的,也就是不允许继承。

        String 和 Long、Integer、Double 等基础类型的包装类都具备不可变性,这些对象的线程安

全性都是靠不可变性来保证的。

        不可变性的类,需要提供类似修改的功能时:创建一个新的不可变对象。

      享元模式

        不可变性的类,修改的是创建一个新的不可变对象,享元模式可以避免创建重复对象。

        享元模式本质上其实就是一个对象池,利用享元模式创建对象的逻辑:创建之前,首先去对

象池里看看是不是存在;如果已经存在,就利用对象池里的对象;如果不存在,就会新创建一个对

象,并且把这个新创建出来的对象放进对象池里。        

        Long 内部维护了一个静态的对象池,仅缓存了[-128,127]之间的数字,这个对象池在 JVM 启

动的时候就创建好了,而且这个对象池一直都不会变化。

        基本上所有的基础类型的包装类都不适合做锁,因为它们内部用到了享元模式,这会导致看

上去私有的锁,其实是共有的。详见:协作篇章,用锁的注意要点模块。

写时复制模式 Copy-on-Write

        原理:在有写操作时,复制共享的数据;

        使用场景:改动不大,数据不多,但是访问量很大,对性能高要求很高;例如:负载均衡的

路由表。

        CopyOnWriteArrayList 和 CopyOnWriteArraySet 两个 Copy-on-Write 容器;这两个容器实现

的读操作是无锁的,所以读取性能很好;

        Copy-on-Write 的缺点就是消耗内存。所有数据的修改都需要复制一份。

        Java 中的基本数据类型 String、Integer、Long 等都是基于 Copy-on-Write 方案实现的。

线程本地存储模式 - ThreadLocal

        每个线程都拥有自己的变量,彼此之间不共享,也就没有并发问题了。

        Java 语言中的ThreadLocal就是线程本地存储模式的实现;

        Thread持有ThreadLocalMap,ThreadLocalMap中包含的是ThreadLocal和对应的值;

        

CAS和原子类

        CAS是CPU指令,全称是 Compare And Swap,即“比较并交换”;CAS 指令本身是能够保证

原子性的;

        CAS 指令包含 3 个参数:共享变量的内存地址 A、用于比较的值 B 和共享变量的新值 C;并

且只有当内存中地址 A 处的值等于 B 时,才能将内存中地址 A 处的值更新为新值 C。

        CAS 方案中,有一个问题可能会常被你忽略,那就是 ABA 的问题。

        在需要关心ABA问题的场景下,需要做进一步的检查,校验A是否发生变化;

        Java并发包里提供的原子类分为五个类别:原子化的基本数据类型、原子化的对象引用类

型、原子化数组、原子化对象属性更新器和原子化的累加器。

      原子化的基本数据类型

        AtomicBoolean、AtomicInteger 和 AtomicLong;

        具备原子化的运算和赋值和修改操作;

        getAndAdd(delta)

        compareAndSet(expect, update)

        getAndUpdate(func)

        

      原子化的对象引用类型

        AtomicReference、AtomicStampedReference 和 AtomicMarkableReference

        具备原子化的运算和赋值和修改操作;

        AtomicStampedReference 和 AtomicMarkableReference 这两个原子类可以解决 ABA         问题。

      原子化数组

        AtomicIntegerArray、AtomicLongArray 和 AtomicReferenceArray

      原子化对象属性更新器

        tomicIntegerFieldUpdater、AtomicLongFieldUpdater 和 AtomicReferenceFieldUpdater,利

用它们可以原子化地更新对象的属性;

        被修改的对象属性必须是 volatile 类型的,只有这样才能保证可见性;如果对象属性不是

volatile 类型的,newUpdater() 方法会抛出 IllegalArgumentException 这个运行时异常。

        

      原子化的累加器

        DoubleAccumulator、DoubleAdder、LongAccumulator 和 LongAdder

        执行累加操作,相比原子化的基本数据类型,速度更快,但是不支持 compareAndSet() 方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值