• 共享模型之无锁


    1. 共享模型之无锁


    管程即monitor是阻塞式的悲观锁实现并发控制,同样可以非阻塞式的乐观锁的来实现并发控制

    1.1 问题提出

    有如下需求,保证account.withdraw取款方法的线程安全

    1. public class Test5 {
    2.     public static void main(String[] args) {
    3.         Account.demo(new AccountUnsafe(10000));
    4.     }
    5. }
    6. class AccountUnsafe implements Account {
    7.     private Integer balance;
    8.     public AccountUnsafe(Integer balance) {
    9.         this.balance = balance;
    10.     }
    11.     @Override
    12.     public Integer getBalance() {
    13.         return balance;
    14.     }
    15.     @Override
    16.     
    17.     public void  withdraw(Integer amount) {
    18.         // 通过这里加锁就可以实现线程安全,不加就会导致结果异常
    19.         synchronized (this){
    20.             balance -= amount;
    21.         }
    22.     }
    23. }
    1. interface Account {
    2.     // 获取余额
    3.     Integer getBalance();
    4.     // 取款
    5.     void withdraw(Integer amount);
    6.     /**
    7.      * 方法内会启动 1000 个线程,每个线程做 -10 元 的操作
    8.      * 如果初始余额为 10000 那么正确的结果应当是 0
    9.      */
    10.     static void demo(Account account) {
    11.         List ts = new ArrayList<>();
    12.         long start = System.nanoTime();
    13.         for (int i = 0; i < 1000; i++) {
    14.             ts.add(new Thread(() -> {
    15.                 account.withdraw(10);
    16.             }));
    17.         }
    18.         ts.forEach(Thread::start);
    19.         ts.forEach(t -> {
    20.             try {
    21.                 t.join();
    22.             } catch (InterruptedException e) {
    23.                 e.printStackTrace();
    24.             }
    25.         });
    26.         long end = System.nanoTime();
    27.         System.out.println(account.getBalance()
    28.                 + " cost: " + (end-start)/1000_000 + " ms");
    29.     }
    30. }

    解决思路-无锁
    上面的代码中可以使用synchronized加锁操作来实现线程安全,但是synchronized加锁操作太耗费资源,这里我们使用无锁来解决此问题

    1. class AccountSafe implements Account{
    2.     AtomicInteger atomicInteger ;
    3.     
    4.     public AccountSafe(Integer balance){
    5.         this.atomicInteger =  new AtomicInteger(balance);
    6.     }
    7.     
    8.     @Override
    9.     public Integer getBalance() {
    10.         return atomicInteger.get();
    11.     }
    12.     @Override
    13.     public void withdraw(Integer amount) {
    14.         // 核心代码
    15.         while (true){
    16.             int pre = getBalance();
    17.             int next = pre - amount;
    18.             if (atomicInteger.compareAndSet(pre,next)){
    19.                 break;
    20.             }
    21.         }
    22.         // 可以简化为下面的方法
    23.         // balance.addAndGet(-1 * amount);
    24.     }
    25. }

    compareAndSet(pre, next)会比较当前atomicInteger对象的值是否等于pre如果相等,则将其更新为next。这个操作是原子的,即保证在多线程环境下不会被打断,防止并发冲突。


    1.2 CAS 与 volatile


    1.2.1 CAS

    CAS 的全称是 Compare And Swap(比较与交换) ,用于实现乐观锁,被广泛应用于各大框架中。CAS 的思想很简单,就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新。

    CAS 是一个原子操作,底层依赖于一条 CPU 的原子指令

     

    前面看到的AtomicInteger的解决方法,内部并没有用锁来保护共享变量的线程安全。那么它是如何实现的呢?

    1.     @Override
    2.     public void withdraw(Integer amount) {
    3.         // 核心代码
    4.         // 需要不
  • 相关阅读:
    ASM3142 USB 3.1控制芯片_ ASM3242 USB 3.2 2x2 控制器
    LeetCode题练习与总结:括号生成
    其实 Gradle Transform 就是个纸老虎 —— Gradle 系列(4)
    土壤温湿度传感器
    docker的使用方法
    Windows下mmap的等价实现
    计算机的计算单位
    DASCTF 2022十月挑战赛 web
    网络的层次
    我的世界Minecraft Java开服教程(Windows)开服器开服包下载开服网站服务器开服核心开服端开服软件mac版Java启动器资源包
  • 原文地址:https://blog.csdn.net/weixin_50458070/article/details/133853965