实战Java高并发程序设计-07原子操作

xiaoxiao2021-02-28  109

悲观与乐观

对于并发而言,锁是一种悲观策略。总是假设每一次临界区操作都会产生冲突,因此,必须每次操作都小心翼翼。如果有多个线程访问临界区资源,就牺牲性能让线程进行等待,使得线程阻塞。而无锁是一种乐观的策略,它会假设对资源的访问时没有冲突的,不需要等待,所有线程都可用不停顿的执行。那么在遇到冲突的情况下采用一种叫做比较交换技术(CAS Compare And Swap)来鉴别线程冲突,一旦检查到冲突产生,就重试当前操作,直到没有冲突为止.

Cas算法

cas算法 示例: 在cas算法中包含三个参数 V,E,N 。 V表示要更新的变量,E表示预期值,N表示新值。仅当V等于E时,才会将V设置为N,如果V不等于E,说明其他线程做了更新,则当前线程什么都不做。最后cas返回当前V的真实值。CAS操作是抱着乐观的态度进行的,它总是认为自己的操作可以成功。当多个线程同时操作一个变量时,只会有一个会操作成功,其他的都会失败。 而原子操作则是在cas的基础上,写入一个while(true) 在循环中,操作成功的线程就会跳出,而失败的线程在循环里面继续执行,直到成功操作为止。

原子整数(AtomicInteger)

import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; public class M { private static AtomicInteger count = new AtomicInteger(); private static int c = 0; static class T implements Runnable{ @Override public void run() { for(int i = 0 ; i < 100 ; i++){ try { Thread.sleep(new Random().nextInt(100)); } catch (InterruptedException e) { e.printStackTrace(); } count.addAndGet(1); c++; } } } public static void main(String[] args) { for(int i = 0 ; i < 5 ; i++){ new Thread(new T()).start(); } while(true){ System.out.println(count.get()); System.out.println("c : " + c); } } }

输出结果 count 会非常稳定 最终等于 500 而 c 不稳定小于等于500

与AtomicInteger类似的还有AtomicLong,AtomicBoolean分别表示long,boolean类型.

原子的对象引用(AtomicReference)

AtomicReference与AtomicInteger非常类似,不同之处在于AtomicInteger是对于整数的封装,而AtomicReference是对于普通对象的引用,也就是说它可以保证在修改对象的引用时线程的安全性。

带时间梭的原子对象引用(AtomicStampedReference)

线程判断对象是否可以正取写入的条件时对象的当前值和期望值是否一致,一般情况下下都是没有问题的。但是存在特殊情况,比如:这个对象的值被其他线程改变了之后,又改了回去。进行了两次修改恢复到了旧的数值,这样的话当前线程是无法判断是否被更改过.而AtomicStampedReference可以解决这个问题.

数组也能无锁(AtomicIntegerArray)

除了基本数据类型之外,JDK还提供了数组等结构,AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray。分别表示整数原子数组,长整型原子数组,对象原子数组。

普通变量也能原子操作

AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater

转载请注明原文地址: https://www.6miu.com/read-30880.html

最新回复(0)