欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-04 17:18:12
...
  • AQS

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

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

  • 应用类

    • 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底层java多线程与高并发(2) -- AQS,CAS,unsafe类
    java多线程与高并发(2) -- AQS,CAS,unsafe类
相关标签: java 多线程