java多线程与高并发(2) -- AQS,CAS,unsafe类

  • AQS
    在这里插入图片描述
    • 抽象类,相当于一个锁。维护的是volatile int state和一个FIFO线程等待队列(队列节点为线程的信息)
    • 子抽象类sync
    •   - sync的实现类FairSync/NonfairSync
        - 其他子类调用方式为引用sync作为他的一个成员变量
      

在这里插入图片描述

  • 应用类

    • ReentrantLock(见锁)

    • CountDownlatch

        1.new CountDownLatch(10) 初始化的时候将state值设置为10
        2.await()  尝试获取锁,获取  state值是否等于0,若不等于0,则将node节点加入到等待队列中park锁住
        3.可以多个线程同时进行 await()
        4.CountDown()  cas 将state值-1  ,如果-1之后的值==0,cas移除等待队列中的节点,释放锁,返回true
        5.例子: 火箭发射: 各个线程检查(燃料,温控,设备,雷达),检查完毕进行发射。
        练习:???
      
    • CyclicBarrier

        1.CyclicBarrier barrier = new CyclicBarrier(20, () -> System.out.println("满人"));  barrier.await();
        2.barrier.await();  -->  利用lock 然后condition.await()
        3.party的数量进行-- 如果减到0,就执行runnable,并且释放锁condition.signalAll()
        4.可循环利用,reset()之后 是和初始化的时候和线程都完成的时候的状态一样。
        5.底层用的是 reentrantLock 和 condition进行控制的。
      
    • Semaphore

       1.new Semaphore(1,true)  ,如果是一个就是锁,如果是多个就是多线程限流,两个参数,另外一个参数是公平非公平
       2.acquire()  获取锁,和CountDownLatch源码类似
       		sync.acquireSharedInterruptibly(1);
       3.release()  释放锁,和CountDownLatch源码类似
        		sync.releaseShared(1);
       4.例子:6辆车抢3个车位
       5.多线程访问同一个资源,限制连接数
      
    • Worker

  • CAS

    • 采用循环的方式获取锁,好处:减少线程上下文切换的消耗,缺点:循环会消耗CPU

    • 源码:

       	1.volatile保证线程可见性
       	2.cas保证原子性,new对象初始化的时候,会拿到这个值的valueOffset 内存地址。
       	3.var1是本类对象,var2是valueOffset,通过内存地址获取var5.
       	4.比较的时候还是通过var1和var2获取新的值,与var5比较,如果一样跳出循环,返回var5,如果不一样重新取var5,然后在进行过compareAndSet。
       	5.返回var5后进行值的加减。
       	6.CAS(expect,update) --- > 更新到jvm中的值为 var5 + var4  返回var5在外层进行加1并返回。
       	7.unsafe类是rt包下 的,jvm通过此类可以直接通过源语对操作系统的内存进行操作。这个保证cas的原子性。
      
    • 比较并交换的底层实现

       unsafe.compareAndSwap  ---> C++ atomic.cmpxchg ---汇编 lock_if_mp cmpxchg  cmpxchg   (比较并交换)是序列化的,单cpu 是原子操作,多CPU的时候, cmpxchg不是原子性的 需要前面加lock  ,lock 是在执行后面指令的时候锁定一个 北桥信号。
      
    • 手写一个自旋锁

    • 1.unsafe类方式: 反射获取unsafe类 +setaccessible+valueoffset+volatile value+unsafe.cas


```java
public class MyCas2 {

    private static Unsafe unsafe = null;//Unsafe.getUnsafe();
    private static final long valueOffset;
    private volatile int value1;
    private static Field unsafeField = null;
    static {
        try {
            unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            unsafe = (Unsafe) unsafeField.get(null);
            valueOffset = unsafe.objectFieldOffset
                    (MyCas2.class.getDeclaredField("value1"));
        } catch (Exception ex) { throw new Error(ex); }
    }


    public void lock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + " come in");
        while (!unsafe.compareAndSwapInt(this,valueOffset,0,1)){
        }

    }

    public void unlock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + " out");
        unsafe.compareAndSwapInt(this,valueOffset,1,0);
    }

    public static void main(String[] args) {
        MyCas2 myCas = new MyCas2();
        new Thread(()->{
            myCas.lock();
            try {
                System.out.println("EXCUTING " + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myCas.unlock();
        },"t1").start();

        new Thread(()->{

            myCas.lock();
            try {
                System.out.println("EXCUTING " + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myCas.unlock();
        },"t2").start();

    }
}```

2.atomicInteger方式:把0更新为1,解锁在更新回来

public class MyCas {

    private AtomicInteger atm = new AtomicInteger(0);
    private AtomicReference<Thread> atomicReference= new AtomicReference<>();

    public void lock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + " come in");
        while (!atomicReference.compareAndSet(null,thread)){
        }

    }

    public void unlock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + " out");
        atomicReference.compareAndSet(thread,null);
    }

    public void lock1(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + " come in");
        while (!atm.compareAndSet(0,1)){
        }

    }

    public void unlock1(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + " out");
        atm.compareAndSet(1,0);
    }


    public static void main(String[] args) {
        MyCas myCas = new MyCas();
        new Thread(()->{
            myCas.lock1();
            try {
                System.out.println("EXCUTING " + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myCas.unlock1();
        },"t1").start();

        new Thread(()->{

            myCas.lock1();
            try {
                System.out.println("EXCUTING " + Thread.currentThread().getName());
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myCas.unlock1();
        },"t2").start();

    }
}
  • unsafe类
  • java 调 C/C++ 调 汇编
  • 可以直接拿到类的成员变量的内存进行操作
  • 可以load class 通过把class文件转化为字节数组的形式。
  • cas调用的是unsafe类的方法
  • cas底层在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值