Java原子引用

1、 原子引用

为什么需要原子引用?因为引用类型也需要被保护

  • AtomicReference
  • AtomicMarkableReference
  • AtomicStampedReference
package com.sharing_model.no_lock;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 原子引用
 */
public class AtomicReferenceTest {
    public static void main(String[] args) {
        DecimalAccount.demo(new DecimalAccountCas(new BigDecimal("10000")));
    }
}

class DecimalAccountCas implements DecimalAccount {

    private AtomicReference<BigDecimal> balance;

    public DecimalAccountCas(BigDecimal balance) {
        this.balance = new AtomicReference<>(balance);
    }

    @Override
    public BigDecimal getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(BigDecimal amount) {
        while (true) {
            BigDecimal prev = balance.get();
            BigDecimal next = prev.subtract(amount);

            if (balance.compareAndSet(prev, next)) {
                break;
            }
        }
    }
}

interface DecimalAccount {
    //获取余额
    BigDecimal getBalance();

    //取款
    void withdraw(BigDecimal amount);

    static void demo(DecimalAccountCas account) {
        List<Thread> ts = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(new BigDecimal(10));
            }));
        }

        long start = System.nanoTime();
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        long end = System.nanoTime();
        System.out.println("剩余钱数: " + account.getBalance());
    }
}

2、 ABA问题

package com.sharing_model.no_lock;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 原子引用
 */
public class AtomicReferenceTest {
    public static void main(String[] args) {
        DecimalAccount.demo(new DecimalAccountCas(new BigDecimal("10000")));
    }
}

class DecimalAccountCas implements DecimalAccount {

    private AtomicReference<BigDecimal> balance;

    public DecimalAccountCas(BigDecimal balance) {
        this.balance = new AtomicReference<>(balance);
    }

    @Override
    public BigDecimal getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(BigDecimal amount) {
        while (true) {
            BigDecimal prev = balance.get();
            BigDecimal next = prev.subtract(amount);

            if (balance.compareAndSet(prev, next)) {
                break;
            }
        }
    }
}

interface DecimalAccount {
    //获取余额
    BigDecimal getBalance();

    //取款
    void withdraw(BigDecimal amount);

    static void demo(DecimalAccountCas account) {
        List<Thread> ts = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(new BigDecimal(10));
            }));
        }

        long start = System.nanoTime();
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        long end = System.nanoTime();
        System.out.println("剩余钱数: " + account.getBalance());
    }
}

3、 AtomicStampedReference

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wg16MBkV-1607688054940)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201206125653337.png)]

package com.sharing_model.no_lock;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 通过添加Stamp(版本号),来判断是否被人修改过,从而解决ABA问题
 */
public class AtomicStampedReferenceTest {
    static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);

    public static void main(String[] args) throws InterruptedException {
        //获取这个变量A的值和版本号
        String prev = ref.getReference();  //A
        int stamp = ref.getStamp(); //0
        System.out.println("初始版本号: " +stamp );
        other();
        Thread.sleep(1000);
        System.out.println("所有修改完成之后的版本号: " + ref.getStamp()); //2
        //尝试修改为C
        System.out.println("change A -> C : " + ref.compareAndSet(prev, "C", stamp, stamp + 1));
    }

    private static void other() throws InterruptedException {
        new Thread(() -> {
            int stamp = ref.getStamp();
            System.out.println("A -> B之前的版本号: " + stamp);
            System.out.println("change A -> B: " + ref.compareAndSet(ref.getReference(), "B", stamp, stamp + 1));

            },"t1").start();

        Thread.sleep(500);

        new Thread(() -> {
            int stamp = ref.getStamp();
            System.out.println("B -> A之前的版本号: " + stamp);
            System.out.println("change B -> A: " + ref.compareAndSet(ref.getReference(), "A", stamp, stamp +1));
        },"t2").start();
    }
}

4、 AtomicMarkableReference

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5expdtBT-1607688054951)(C:/Users/lenovo/AppData/Roaming/Typora/typora-user-images/image-20201206133242837.png)]

package com.sharing_model.no_lock;

import java.util.concurrent.atomic.AtomicMarkableReference;

/**
 *AtomicMarkableReference: 
 * 和 AtomicStampedReference 不同之处在于,不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference
 */
public class AtomicMarkableReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        GarbageBag bag = new GarbageBag("装满了垃圾");
        //参数 mark 可以看成一个标记,表示垃圾袋满了
        AtomicMarkableReference<GarbageBag> ref = new AtomicMarkableReference<>(bag, true);
        System.out.println("start...");
        GarbageBag prev = ref.getReference();
        System.out.println(prev.toString());

        Thread.sleep(1000);

        System.out.println("想更换一只新垃圾袋?");
        boolean success = ref.compareAndSet(prev, new GarbageBag("空垃圾袋"),true, false);
        System.out.println("换了吗?" + success);
        System.out.println(ref.getReference().toString());
    }
}

class GarbageBag {
    String value;

    public GarbageBag(String value) {
        this.value = value;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值