juc并发编程(二)

19、深入理解CAS

1)什么是CAS

深入研究底层!!!

package com.kuang.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
    //CAS
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //compareAndSet:比较并交换!!
        /**
         * 期望、更新
         *     public final boolean compareAndSet(int expect, int update) {
         *         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
         *     }
         *
         *     CAS:是CPU的并发原语
         */
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        // 如果我期望的值达到了就更新,否则就不更新
        System.out.println(atomicInteger.get());
//        atomicInteger.getAndIncrement();
        /**
         *     public final int getAndIncrement() {
         *         return unsafe.getAndAddInt(this, valueOffset, 1);
         *     }
         */

        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        // 如果我期望的值达到了就更新,否则就不更新
        System.out.println(atomicInteger.get());
    }
}

2) Unsafe类
  atomicInteger.getAndIncrement();

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环!

缺点:

1、循环会耗时
2、一次性只能保证一个共享变量的原子性
3、ABA问题

3)CAS:ABA 问题

狸猫换太子

在这里插入图片描述

package com.kuang.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {
    //CAS
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //compareAndSet:比较并交换!!
        /**
         * 期望、更新
         *     public final boolean compareAndSet(int expect, int update) {
         *         return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
         *     }
         *
         *     CAS:是CPU的并发原语
         */
//        对于我们平时写的SQL:乐观锁
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        // 如果我期望的值达到了就更新,否则就不更新
        // CAS 是CPU的并发原语!
        System.out.println(atomicInteger.get());
//        atomicInteger.getAndIncrement();
        /**
         *     public final int getAndIncrement() {
         *         return unsafe.getAndAddInt(this, valueOffset, 1);
         *     }
         */

        System.out.println(atomicInteger.compareAndSet(2021, 2020));
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(2020, 6666));
        System.out.println(atomicInteger.get());
    }
}

20、原子引用

1) 解决ABA问题,引入原子引用!

对应的思想:乐观锁!

带版本号的原子操作

在这里插入图片描述
在这里插入图片描述

package com.kuang.cas;

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

public class Test {
    // AtomicStampedReference 注意,如果泛型是包装类,注意对象的引用问题
    static AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1, 1);

    public static void main(String[] args) {

        new Thread(()->{
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("a1="+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //version+1
           atomicInteger.compareAndSet(1, 2,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1);

            System.out.println("a2="+atomicInteger.getStamp());

            System.out.println(atomicInteger.compareAndSet(2, 1,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1));

            System.out.println("a3="+atomicInteger.getStamp());
        },"a").start();

//        乐观锁的原因相同
        new Thread(()->{
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("b1="+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicInteger.compareAndSet(1, 6,
                    stamp, stamp + 1));

            System.out.println("b2="+atomicInteger.getStamp());
        },"b").start();
    }
}

21、各种锁的理解

1)公平锁、非公平锁

公平锁:非常公平,不能够插队,必须先来后到!
非公平锁:非常不公平,可以插队(默认都是非公平的)
在这里插入图片描述

2)可重入锁

可重入锁(递归锁)
在这里插入图片描述

package com.kuang.lock;

// synchronized
public class Demo01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(()->{
            phone.sms();
        },"a").start();
        new Thread(()->{
            phone.sms();
        },"b").start();
    }
}
class Phone{
    public synchronized void sms(){
        System.out.println(Thread.currentThread().getName()+"Sms");
        call();// 这里也有锁
    }
    public synchronized void call(){
        System.out.println(Thread.currentThread().getName()+"call");
    }
}
package com.kuang.lock;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo02 {
    public static void main(String[] args) {
        Phone2 phone = new Phone2();

        new Thread(()->{
            phone.sms();
        },"a").start();
        new Thread(()->{
            phone.sms();
        },"b").start();
    }
}
class Phone2{
    Lock lock=new ReentrantLock();
    public  void sms(){
        lock.lock();
        //lock 锁必须要配对,否则就会死锁
        try{
            System.out.println(Thread.currentThread().getName()+"Sms");
            call();// 这里也有锁
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
    public  void call(){
        lock.lock();
        try{
            System.out.println(Thread.currentThread().getName()+"call");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }}
}
3)自旋锁

spinlock
在这里插入图片描述

package com.kuang.lock;

import jdk.nashorn.internal.ir.CallNode;

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

//自旋锁
public class SpinlockDemo {
    //int   0
    //Thread  null
    AtomicReference<Thread> atomicReference=new AtomicReference<>();
//    加锁
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"==>mylock");
        //自旋锁
        while(!atomicReference.compareAndSet(null,thread)){

        }
    }
//    解锁
    public void myUnLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"==>myUnlock");
        atomicReference.compareAndSet(thread,null);
    }


}

测试:

package com.kuang.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TestSpinlock {
    public static void main(String[] args) throws InterruptedException {
//        ReentrantLock reentrantLock = new ReentrantLock();
//        reentrantLock.lock();
//        reentrantLock.unlock();

        //最底层使用了自旋锁
        SpinlockDemo spinlockDemo = new SpinlockDemo();
        new Thread(()->{
            spinlockDemo.myLock();
            try{
                TimeUnit.SECONDS.sleep(3);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                spinlockDemo.myUnLock();
            }
        },"a").start();

        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            spinlockDemo.myLock();
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                spinlockDemo.myUnLock();
            }
        },"b").start();

    }
}

运行结果:
在这里插入图片描述

4)死锁

1、死锁是什么?
在这里插入图片描述
2、死锁的排除

package com.kuang.lock;

import java.util.concurrent.TimeUnit;

public class DeadLockDemo {
    public static void main(String[] args) {
        String lockA="lockA";
        String lockB="lockB";

        new Thread(new MyThread(lockA,lockB),"T1").start();
        new Thread(new MyThread(lockB,lockA),"T2").start();
    }
}
class MyThread implements Runnable{
    private String lockA;
    private String lockB;

    @Override
    public void run() {
        synchronized (lockA){
            System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"->get"+lockB);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"->get"+lockA);
            }
        }
    }

    public MyThread(String lockA,String lockB){
        this.lockA=lockA;
        this.lockB=lockB;
    }
}

3、解决问题
①使用 jps -l 定位进程号
在这里插入图片描述

②使用 jstack 进程号 查看进程信息
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值