【并发知识点】CAS的实现原理及应用

2 篇文章 0 订阅

系列文章目录

AQS的实现原理及应用
CAS的实现原理及应用

在这里插入图片描述



前言

本章节介绍CAS概念、实现原理,并通过java代码应用,最终模拟赛龙舟比赛。

1、CAS的概念

CAS的全称为:CompareAndSwap,直译为对比和交换。
CAS实际是普遍处理器都支持的一条指令,这条指令通过判断当前内存值V、旧的预期值A、即将更新的值B是否相等来对比并设置新值,从而实现变量的原子性。
Synchronized会线程阻塞称为悲观锁,CAS不会使线程阻塞称为乐观锁。悲观锁其他没有获取锁的线程是不会执行代码的,而乐观锁是可以使多个线程同时访问代码,可是会判断是否有更新决定是否重新执行。

2、CAS的实现原理

CAS的原理:通过三个参数,当前内存的变量值V、旧的预期值A、即将更新的值B。通过判断是V和A是否相等查看当前变量值是否被其他线程改变,如果相等则变量没有被其他线程更改,就把B值赋予V;如果不相等则做自旋操作。
举例:假设i的初始值为0,现两线程分别执行i++操作,看看CAS会如何执行:

1线程:A = 0,B = 1
2线程:A = 0,B = 1

此时两个线程的旧的期望值A、更新的B值都是一样的
假设1线程先执行,线程1从内存中拿到i的值V,此时V等于0,刚好和旧的期望值A相等,就把更新的值B赋值到内存i值V中。
2线程执行时,此时拿到内存的V值为1,和旧的预期值0不想等,则不做更新B的赋值操作,通过自旋把旧的预期值A=V,并再次确定CAS指令。
在这里插入图片描述

JDK提供的原子操作类就是基于CAS来实现原子性,比如:AtomicInteger、AtomicIntegerArray、AtomicDouble、AtomicBoolean等

3、单JVM内锁CAS实现

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/***
 * @title AtomicExample
 * @desctption CAS
 * @author Kelvin
 * @create 2023/6/14 17:08
 **/
public class AtomicExample {
    private static Map<String, Boolean> map = new HashMap<>();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //未加锁
        map.put("lock", true);
        for (int i = 0; i < 20; i++) {
            int finalI = i;
            executorService.submit(
                    () -> {
                        boolean isRotate = true;
                        while (isRotate) {
                            boolean vLock = map.get("lock");
                            if( vLock ) {
                                boolean aLock = map.get("lock");
                                if( vLock == aLock ) {
                                    //执行业务逻辑
                                    //加锁
                                    map.put("lock", false);
                                    System.out.println( "执行业务逻辑, i: " + finalI);
                                    try {
                                        Thread.sleep(2000);
                                    } catch (InterruptedException e) {
                                        throw new RuntimeException(e);
                                    }
                                    isRotate = false;
                                    //释放锁
                                    map.put("lock", true);
                                } else {
                                    System.out.println("自旋,重新获取锁!");
                                    continue;
                                }
                            }
                        }
                    }
            );
        }

        Thread.sleep(20 * 1000);
        System.out.println("end");
        executorService.shutdown();
        
    }
}

3.1、效果

执行业务逻辑, i: 1
执行业务逻辑, i: 5
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 4
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 10
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 9
执行业务逻辑, i: 2
自旋,重新获取锁!
执行业务逻辑, i: 3
自旋,重新获取锁!
执行业务逻辑, i: 0
执行业务逻辑, i: 12
执行业务逻辑, i: 11
执行业务逻辑, i: 8
执行业务逻辑, i: 6
执行业务逻辑, i: 7
执行业务逻辑, i: 14
自旋,重新获取锁!
执行业务逻辑, i: 15
执行业务逻辑, i: 16
执行业务逻辑, i: 18
自旋,重新获取锁!
自旋,重新获取锁!
执行业务逻辑, i: 17
执行业务逻辑, i: 19
执行业务逻辑, i: 13
end

4、模拟赛龙舟比赛

在这个程序中,我们将使用Java的AtomicInteger来实现一个裁判的计时器,模拟一个赛龙舟比赛中多支队伍竞争的场景。每个队伍都会在启动时创建一个独立的线程,并在程序中使用LockFreeQueue来模拟龙舟的运动。同时,程序中还会使用CountDownLatch来控制所有龙舟同时开始比赛,并使用CyclicBarrier来模拟所有队伍完成比赛后的庆祝活动。

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class DragonBoatRace {
    private static final int TEAM_NUM = 4; // 参赛队伍数
    private static final int BOAT_NUM = 1; // 龙舟数量
    private static final Random random = new Random();
    private static final AtomicInteger time = new AtomicInteger(0);
    private static final CountDownLatch startLatch = new CountDownLatch(TEAM_NUM);
    private static final CyclicBarrier finishBarrier = new CyclicBarrier(TEAM_NUM + 1);
    private static final LockFreeQueue<Integer> queue = new LockFreeQueue<>();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(TEAM_NUM);
        for (int i = 0; i < TEAM_NUM; i++) {
            executorService.submit(new Team(i + 1));
        }
        startLatch.await(); // 等待所有队伍准备就绪
        System.out.println("比赛开始!");
        for (int i = 0; i < BOAT_NUM; i++) {
            new Thread(new Boat(i + 1)).start();
        }
        System.out.println("龙舟已经准备好!");
        finishBarrier.await(); // 等待所有队伍完成比赛
        System.out.println("所有队伍完成比赛,开始庆祝!");
        executorService.shutdown(); // 关闭线程池
    }

    static class Team implements Runnable {
        private final int teamId;

        public Team(int teamId) {
            this.teamId = teamId;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(1000 * teamId); // 模拟队伍准备时间
                System.out.println("队伍" + teamId + "已准备就绪!");
                startLatch.countDown(); // 准备就绪,计数器减一
                queue.add(1); // 龙舟前进一步
                while (time.get() < 2000) { // 等待龙舟到达终点
                    Thread.yield();
                }
                System.out.println("队伍" + teamId + "已完成比赛,用时" + time.get() + "ms!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                try {
                    finishBarrier.await(); // 等待其他队伍完成比赛
                    System.out.println("队伍" + teamId + "正在庆祝!");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class Boat implements Runnable {
        private final int boatId;

        public Boat(int boatId) {
            this.boatId = boatId;
        }

        @Override
        public void run() {
            while (!queue.isEmpty()) { // 龙舟前进,直到到达终点
                if (queue.poll() != null) {
                    time.addAndGet(random.nextInt(10) + 1); // 龙舟前进一步,用时1~10ms
                }
            }
            try {
                finishBarrier.await(); // 等待所有队伍完成比赛
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    static class LockFreeQueue<E> {
        private static class Node<E> {
            final E item;
            volatile Node<E> next;

            Node(E item) {
                this.item = item;
            }
        }

        private volatile Node<E> head;
        private volatile Node<E> tail;

        public boolean isEmpty() {
            return head == null;
        }

        public void add(E item) {
            Node<E> node = new Node<>(item);
            while (true) {
                Node<E> last = tail;
                Node<E> next = last == null ? head : last.next;
                if (last == tail) {
                    if (next == null) {
                        if (compareAndSetNext(last, null, node)) {
                            compareAndSetTail(last, node);
                            return;
                        }
                    } else {
                        compareAndSetTail(last, next);
                    }
                }
            }
        }

        public E poll() {
            while (true) {
                Node<E> first = head;
                Node<E> last = tail;
                Node<E> next = first == null ? null : first.next;
                if (first == head) {
                    if (first == last) {
                        if (next == null) {
                            return null;
                        }
                        compareAndSetTail(last, next);
                    } else {
                        E item = next.item;
                        if (compareAndSetHead(first, next)) {
                            return item;
                        }
                    }
                }
            }
        }

        private boolean compareAndSetHead(Node<E> expect, Node<E> update) {
            return unsafe.compareAndSwapObject(this, headOffset, expect, update);
        }

        private boolean compareAndSetTail(Node<E> expect, Node<E> update) {
            return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
        }

        private boolean compareAndSetNext(Node<E> node, Node<E> expect, Node<E> update) {
            return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
        }

        private static final sun.misc.Unsafe unsafe;
        private static final long headOffset;
        private static final long tailOffset;
        private static final long nextOffset;

        static {
            try {
                unsafe = getUnsafe();
                Class<?> k = LockFreeQueue.class;
                headOffset = unsafe.objectFieldOffset(k.getDeclaredField("head"));
                tailOffset = unsafe.objectFieldOffset(k.getDeclaredField("tail"));
                nextOffset = unsafe.objectFieldOffset(Node.class.getDeclaredField("next"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }

        private static sun.misc.Unsafe getUnsafe() throws Exception {
            Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (sun.misc.Unsafe) field.get(null);
        }
    }
}

在这个程序中,我们模拟了4个队伍参加赛龙舟比赛。每个队伍都在启动时创建一个独立的线程,并在比赛前等待1-4s的准备时间。当所有队伍都准备就绪后,裁判发出比赛开始信号,龙舟开始前进。程序中使用LockFreeQueue来模拟龙舟的运动,每次龙舟前进一步,用时1~10ms。当某个队伍完成比赛后,程序会使用CyclicBarrier来等待其他队伍完成比赛,并且进行庆祝活动。

总之,基于CAS的Java多线程程序可以很好地模拟赛龙舟比赛中的多支队伍竞争的场景。通过使用Java的AtomicInteger和LockFreeQueue等基于CAS的同步机制,我们可以实现高效的线程协作和同步操作。

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青花科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值