4、共享模型之无锁

该栏目讲叙多线程基础、共享模型的内存、管程、无锁、不可变设计和多线程并发工具


CAS机制

1、简介

  • 概述:CAS,是 Compare and Swap 的简称,即比较并替换,是乐观锁的一种体现
  • 优点
    • 可以保证变量操作的原子性
    • 并发量不是很高的情况下,使用 CAS 机制比使用锁机制效率更高
    • 在线程对共享资源占用时间较短的情况下,使用 CAS 机制效率也会较高(synchronized 会让线程在没有获得锁的时候,发生上下文切换,进入阻塞)
  • 缺点
    • CPU 开销过大
    • 不能保证代码块的原子性
    • ABA 问题

2、原理

CAS原理

  • 其实 CAS 的底层是 lock cmpxchg 指令(X86架构),在单核 CPU 和多核 CPU 下都能够保证【比较-交换】的原子性
  • 在多核状态下,某个核执行到带 lock 的指令时,CPU 会让总线锁住,当这个核把此指令执行完毕,再开启总线。这个过程中不会被线程的调度机制所打断,保证了多个线程对内存操作的准确性是原子的

3、案例

package com.itnear.atomic;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 转账案例
 */
public class AtomicDemo {

    private final AtomicInteger balance;

    public AtomicDemo(int balance) {
        this.balance = new AtomicInteger(balance);
    }

    /**
     * 转账
     *
     * @param amount 金额
     */
    public void withdraw(int amount) {
        while (true) {
            if (balance.get() <= 0) {
                System.out.println("余额不足,转账失败");
                break;
            }

            final int preAmount = balance.get();
            final int nextAmount = preAmount - amount;
            final boolean flag = balance.compareAndSet(preAmount, nextAmount);
            if (flag) {
                System.out.println("转账成功,当前余额:" + nextAmount);
                break;
            }
        }
    }

    /**
     * 获取金额
     *
     * @return 金额
     */
    public int getAmount() {
        return balance.get();
    }

    public static void main(String[] args) {
        AtomicDemo atomicDemo = new AtomicDemo(10000);
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 1010; i++) {
            threads.add(new Thread(() -> atomicDemo.withdraw(10)));
        }
        threads.forEach(Thread::start);
        threads.forEach(thread -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println("余额:" + atomicDemo.getAmount());
    }

}

原子整型

public class AtomicIntegerDemo {

    private static final AtomicInteger atomicInteger = new AtomicInteger(0);
    private static final AtomicLong atomicInteger = new AtomicLong(0);

    public static void main(String[] args) {
        // 获取并自增
        int value = atomicInteger.getAndIncrement();
        System.out.println("value = " + value);

        // 自增并获取
        value = atomicInteger.incrementAndGet();
        System.out.println("value = " + value);

        // 获取并自减
        value = atomicInteger.getAndDecrement();
        System.out.println("value = " + value);

        // 自减并获取
        value = atomicInteger.decrementAndGet();
        System.out.println("value = " + value);

        // 添加并获取
        value = atomicInteger.addAndGet(5);
        System.out.println("value = " + value);

        // 获取并添加
        value = atomicInteger.getAndAdd(5);
        System.out.println("value = " + value);

        // 更新并获取
        value = atomicInteger.updateAndGet(p -> p + 2);
        System.out.println("value = " + value);

        // 获取并更新
        value = atomicInteger.getAndUpdate(p -> p - 2);
        System.out.println("value = " + value);

        // 获取并计算
        value = atomicInteger.getAndAccumulate(10, (p, x) -> p + x);
        System.out.println("value = " + value);

        // 计算并获取
        value = atomicInteger.accumulateAndGet(10, (p, x) -> p - x);
        System.out.println("value = " + value);

        // 获取
        value = atomicInteger.get();
        System.out.println("value = " + value);
    }

}

原子布尔型

public class AtomicBooleanDemo {

    private static final AtomicBoolean atomicBoolean = new AtomicBoolean();

    public static void main(String[] args) {
        // 获取并设置
        boolean flag = atomicBoolean.getAndSet(true);
        System.out.println("flag = " + flag);

        // 设置
        atomicBoolean.set(false);

        // 获取
        flag = atomicBoolean.get();
        System.out.println("flag = " + flag);
    }

}

原子引用

public class AtomicReferenceDemo {

    public static void main(String[] args) {
        referenceTest();
        stampedReferenceTest();
        markReferenceTest();
    }

    /**
     * AtomicReference类用于对引用类型进行CAS操作,但避免不了ABA问题
     */
    private static void referenceTest() {
        AtomicReference<BigDecimal> atomicReference = new AtomicReference<>();
        // 设置
        atomicReference.set(new BigDecimal(10));
        // 获取
        BigDecimal decimal = atomicReference.get();
        System.out.println("decimal = " + decimal);
        // 获取并设置
        decimal = atomicReference.getAndSet(new BigDecimal(20));
        System.out.println("decimal = " + decimal);
    }

    /**
     * AtomicStampedReference可以给原子引用添加版本号,可以引用变量中途被修改了几次,可以解决ABA问题
     */
    private static void stampedReferenceTest() {
        AtomicStampedReference<String> stampedReference = new AtomicStampedReference<>("A", 0);
        // 获取值
        final String reference = stampedReference.getReference();
        // 获取版本
        final int stamp = stampedReference.getStamp();
        // 比较并设置
        final boolean flag = stampedReference.compareAndSet(reference, "C", stamp, stamp + 1);
        if (flag) {
            System.out.println("更新成功");
        }
    }

    /**
     * AtomicMarkableReference只关心原子引用是否被修改过,也可以解决ABA问题
     */
    private static void markReferenceTest() {
        AtomicMarkableReference<Integer> markReference = new AtomicMarkableReference<>(10, false);
        // 获取值
        final Integer reference = markReference.getReference();
        // 获取标志
        final boolean marked = markReference.isMarked();
        // 比较并设置
        final boolean flag = markReference.compareAndSet(reference, reference + 1, marked, !marked);
        if (flag) {
            System.out.println("更新成功");
        }
    }
}

原子数组

public class AtomicArrayDemo {

    private static final AtomicIntegerArray integerArray = new AtomicIntegerArray(11);
    private static final AtomicLongArray longArray = new AtomicLongArray(10);
    private static final AtomicReferenceArray<BigDecimal> referenceArray = new AtomicReferenceArray<>(10);

    public static void main(String[] args) {
        // 获取并自增
        int value0 = integerArray.getAndIncrement(0);
        System.out.println("value0 = " + value0);

        // 自增并获取
        int value1 = integerArray.incrementAndGet(1);
        System.out.println("value1 = " + value1);

        // 获取并自减
        int value2 = integerArray.getAndIncrement(2);
        System.out.println("value2 = " + value2);

        // 自减并获取
        int value3 = integerArray.decrementAndGet(3);
        System.out.println("value3 = " + value3);

        // 添加并获取
        int value4 = integerArray.addAndGet(4, 5);
        System.out.println("value4 = " + value4);

        // 获取并添加
        int value5 = integerArray.getAndAdd(5, 5);
        System.out.println("value5 = " + value5);

        // 更新并获取
        int value6 = integerArray.updateAndGet(6, p -> p + 2);
        System.out.println("value6 = " + value6);

        // 获取并更新
        int value7 = integerArray.getAndUpdate(7, p -> p - 2);
        System.out.println("value7 = " + value7);

        // 获取并计算
        int value8 = integerArray.getAndAccumulate(8, 10, (p, x) -> p + x);
        System.out.println("value8 = " + value8);

        // 计算并获取
        int value9 = integerArray.accumulateAndGet(9, 10, (p, x) -> p - x);
        System.out.println("value9 = " + value9);

        // 获取
        int value = integerArray.get(10);
        System.out.println("value = " + value);
    }

}

字段更新器

public class AtomicFixedDemo {

    private volatile int value;

    private volatile String msg;

    public static void main(String[] args) {
        integerFieldTest();
        referenceFieldTest();
    }

    /**
     * 整形字段更新器
     */
    private static void integerFieldTest() {
        AtomicIntegerFieldUpdater<AtomicFixedDemo> fieldUpdater =
                AtomicIntegerFieldUpdater.newUpdater(AtomicFixedDemo.class, "value");

        AtomicFixedDemo fixedDemo = new AtomicFixedDemo();
        // 设置
        fieldUpdater.set(fixedDemo, 10);
        // 获取
        final int value = fieldUpdater.get(fixedDemo);
        System.out.println("value = " + value);
        // 比较并设置
        final boolean flag = fieldUpdater.compareAndSet(fixedDemo, value, value + 10);
        System.out.println("修改结果:" + flag);
    }

    /**
     * 引用字段更新器
     */
    private static void referenceFieldTest() {
        AtomicReferenceFieldUpdater<AtomicFixedDemo, String> fieldUpdater =
                AtomicReferenceFieldUpdater.newUpdater(AtomicFixedDemo.class, String.class, "msg");

        AtomicFixedDemo fixedDemo = new AtomicFixedDemo();
        // 设置
        fieldUpdater.set(fixedDemo, "Near");
        // 获取
        final String msg = fieldUpdater.get(fixedDemo);
        System.out.println("msg = " + msg);
        // 比较并设置
        final boolean flag = fieldUpdater.compareAndSet(fixedDemo, msg, "NearJC");
        System.out.println("修改结果:" + flag);
    }

}

原子累加器

public class LongAdderDemo {

    private static final LongAdder longAdder = new LongAdder();

    public static void main(String[] args) {
        // 自增
        longAdder.increment();
        // 自减
        longAdder.decrement();
        // 添加
        longAdder.add(10);
        // 获取值
        final int value1 = longAdder.intValue();
        System.out.println("value1 = " + value1);
        final double value2 = longAdder.doubleValue();
        System.out.println("value2 = " + value2);
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值