1、CAS 原理,Unsafe 原理

CAS: 比较并交换

例子:原子整型(AtomicInteger)

AtomicInteger num = new AtomicInteger(1);

boolean b = num.compareAndSet(1, 2000);

 

Cas 底层有的 Unsafe 类(当前对象,内存偏移量,期望值,更新值)



/**
 * Atomically sets the value to the given updated value
 * if the current value {@code ==} the expected value.
 *
 * @param expect the expected value
 * @param update the new value
 * @return {@code true} if successful. False return indicates that
 * the actual value was not equal to the expected value.
 */
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

unsafe 底层原理 (自旋锁)


 

2、CAS 缺点 

        用的 自旋锁,比较好资源

        只能保证一个共享变量的原子性,多个变量无法保证

        会有ABA问题

 

3、什么是 ABA 问题

        有两条线程: 首先 1线程 将 值改为 A, 然后线程2,将A-> B ->A,接下来 线程1操作cas 成功,但是这个过程是有问题的

 

4、如何解决 ABA 问题

System.out.println("============解决问题===========");
new Thread(() -> {
    boolean b = int2.compareAndSet(100, 101, int2.getStamp(), int2.getStamp() + 1);
    System.out.println(b+",stamp:" +int2.getStamp() + " currValue:" + int2.getReference());
    boolean b1 = int2.compareAndSet(101, 100, int2.getStamp(), int2.getStamp() + 1);
    System.out.println(b1+",stamp:" +int2.getStamp() + " currValue:" + int2.getReference());
}, "t3").start();
new Thread(() -> {
    int stamp = int2.getStamp();
    boolean b = int2.compareAndSet(100, 9999, 1, stamp + 1);
    System.out.println(b+",stamp:" +int2.getStamp() + " currValue:" + int2.getReference());
}, "t3").start();

原子整型,原子引用

 

完整代码

package com.example.study01.common;
import com.example.study01.common.vo.User;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicIntegerStudy {
    static AtomicInteger int1 = new AtomicInteger(101);
    static AtomicStampedReference<Integer> int2 = new AtomicStampedReference<>(100 ,1);
    public static void main(String[] args) {
        AtomicIntegerStudy atomicIntegerStudy = new AtomicIntegerStudy();
//        atomicIntegerStudy.t1();
//        atomicIntegerStudy.t2();
//        atomicIntegerStudy.t3();
        for (int i = 0; i < 20; i++) {
            atomicIntegerStudy.t7();
        }
    }
    /**
     * set 线程不安全问题解决
     */
    Set set1 = new CopyOnWriteArraySet();
    public void t7() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                set1.add(UUID.randomUUID().toString().substring(0, 4));
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":"+ set1);
            }
        }, "t1").start();
    }
    /**
     * set 线程不安全问题重现
     */
    Set set = new HashSet();
    public void t6() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                set.add(UUID.randomUUID().toString().substring(0, 4));
                System.out.println(Thread.currentThread().getName() + ":"+ set);
            }
        }, "t1").start();
    }

    /**
     * 解决 list 的线程安全问题
     */
    List v1 = new Vector();
    List<String> list2 = Collections.synchronizedList(new ArrayList<>());
    List list3 = new CopyOnWriteArrayList();
    public void t5(){
        //解决 t4() 并发修改的问题
        // 方法 1 :new Vector()
        new Thread(() -> {
            list2.add(UUID.randomUUID().toString().substring(0, 8));
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":"+ list2);
        },"th2").start();
        // 方法2 :Collections.synchronizedList(new ArrayList());
        new Thread(() -> {
            v1.add(UUID.randomUUID().toString().substring(0, 8));
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":"+ v1);
        },"th3").start();
        // 方法3:CopyOnWriteArrayList()
        new Thread(() -> {
            list3.add(UUID.randomUUID().toString().substring(0, 8));
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":"+ list3);
        },"th4").start();

    }
    /**
     * list 线程安全问题重现
     */
    List<String> list = new ArrayList<>();
    public void t4() {
        //集合类的不安全问题 java.util.ConcurrentModificationException 并发修改问题
        new Thread( new Runnable(){
            @Override
            public void run() {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }
        },"th1").start();
    }
    /**
     * ABA 问题 产生 以及 解决
     */
    public void t3() {
        // 以下是 ABA 问题的产生
        new Thread(() -> {
            System.out.println(int1.compareAndSet(101, 201)+ "======currValue="+int1.get()+ "=====name:"+ Thread.currentThread().getName());
            System.out.println(int1.compareAndSet(201, 101)+ "======currValue="+int1.get()+ "=====name:"+ Thread.currentThread().getName());
        }, "thread1").start();
        new Thread(() -> {
            TimeUnit.SECONDS.toSeconds(2);
            System.out.println(int1.compareAndSet(101, 2222)+ "======currValue="+int1.get()+ "=====name:"+ Thread.currentThread().getName());
        }, "thread2").start();

         // 以下是问题的解决
        TimeUnit.SECONDS.toSeconds(2);
        System.out.println("============解决问题===========");
        new Thread(() -> {
            boolean b = int2.compareAndSet(100, 101, int2.getStamp(), int2.getStamp() + 1);
            System.out.println(b+",stamp:" +int2.getStamp() + " currValue:" + int2.getReference());
            boolean b1 = int2.compareAndSet(101, 100, int2.getStamp(), int2.getStamp() + 1);
            System.out.println(b1+",stamp:" +int2.getStamp() + " currValue:" + int2.getReference());
        }, "t3").start();
        new Thread(() -> {
            int stamp = int2.getStamp();
            boolean b = int2.compareAndSet(100, 9999, 1, stamp + 1);
            System.out.println(b+",stamp:" +int2.getStamp() + " currValue:" + int2.getReference());
        }, "t3").start();
    }
    public void t2() {
        // ABA 问题(原子引用  AtomicReference)
        User z3 = new User("张三","11");
        User l4 = new User("李四","21");
        AtomicReference<User> atomicReference = new AtomicReference<>(z3);
        boolean b = atomicReference.compareAndSet(z3, l4);
        System.out.println(b+"===currUser="+atomicReference.get());
        boolean b1 = atomicReference.compareAndSet(z3, z3);
        System.out.println(b1 + "===currUser="+atomicReference.get());

    }
    public void t1() {
        // 原子整型 cas
        AtomicInteger num = new AtomicInteger(1);
        boolean b = num.compareAndSet(1, 2000);
        System.out.println(b + "---- currValue="+num.get());
        boolean b1 = num.compareAndSet(1, 3000);
        System.out.println(b1 + "---- currValue="+num.get());
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值