公平锁/非公平锁/可重入锁/递归锁/自旋锁,谈谈你的理解?+手写一个自旋锁

1、公平锁和非公平锁

公平锁 :多个线程申请锁的顺序来获取锁(先来后到
非公平锁 :多个线程通过争抢来获得锁(获取是不按照顺序的)

synchronized,是一个非公平锁
java 中 ReentrantLock 采用不同i的构造方法 可以是公平锁 也可以是非公平锁

    /**
     默认的非公平锁
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

可以通过有参构造 创建一个公平锁

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

在性能上 : 非公平锁的优点在于吞吐量比公平锁大

可重入锁(递归锁)

ReentrantLock 和 synchronized 都是可重入锁

一、什么是可重入锁 ?
线程可以进入任何一个他已经拥有的锁所同步着的代码块

采用synchronized演示

/**
 * 资源类
 */
class Resource{
    public synchronized void reentrySynchronizedDemo(){
        System.out.println("拿到锁进入");
        reentrySynchronized();
    }
    public synchronized void reentrySynchronized(){
        System.out.println("重入锁");
    }
}
public class ReentryLockDemo {
    public static void main (String[] args) {
        Resource resource = new Resource();
        resource.reentrySynchronizedDemo();
    }
}

接下来是采用显示锁Lock 演示

/**
 * 资源类
 */
class Resource{
    Lock lock = new ReentrantLock();
    /**
     * Lock重入锁案例
     */
    public void reentryLockDemo(){
        //上锁
        lock.lock();
        try {
            System.out.println("拿到锁进入");
            reentryLock();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁
        }

    }

    public void reentryLock(){
        //上锁
        lock.lock();
        try {
            System.out.println("重入锁");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//释放锁
        }

    }
}
public class ReentryLockDemo {
    public static void main (String[] args) {
        Resource resource = new Resource();
        resource.reentryLockDemo();
    }
}

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

3、自旋锁

一、什么是自旋锁 ?
就是 尝试获得锁的线程,拿不到锁不会立刻阻塞,而是采取循环的方式去尝试换取锁
优点:可以减少线程的上下文切换
缺点:循环会消耗cpu

例如cas的实现就是采用了自旋锁

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

手写一个自旋锁

/**
 * 自旋锁案例
 */
public class SpinLockDemo {
    //原子引用
    AtomicReference<Thread>  atomicReference = new AtomicReference<>();


    public void myLock(){
        Thread thread = Thread.currentThread();//当前线程
        System.out.println(thread.getName() + "come in");
        //开始自旋锁
        while(!atomicReference.compareAndSet(null,thread));
    }


    public void unlock(){
        Thread thread = Thread.currentThread();//当前线程
        atomicReference.compareAndSet(thread,null);
        System.out.println(thread.getName() + "come out");
    }

    public static void main (String[] args) throws InterruptedException {
        SpinLockDemo spinLockDemo = new SpinLockDemo();
        new Thread(()->{
            spinLockDemo.myLock();
            System.out.println("t1霸占获取锁");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1释放获取锁");
            spinLockDemo.unlock();
        },"t1").start();

        //睡一秒 保证t1先t2
        Thread.sleep(1000);

        new Thread(()->{
            System.out.println("t2尝试自旋获取锁");
            spinLockDemo.myLock();
            System.out.println("t2成功获取到锁");
            spinLockDemo.unlock();
        },"t2").start();

    }
}


结果
在这里插入图片描述

独占锁(写锁)

指锁一次只能被一个线程持有,ReentrantLock 和synchronized 都是独占锁

共享锁(读锁)

指该锁可以被多个线程占有

读写锁

ReentrantReadWriteLock 其读锁是共享锁 ,写锁是独占锁
优点:可以保证并发读是非常高效的,读写,写写,写读过程都是互斥的

案例


/**
 * 读写锁案例
 */
public class ReadWriteDemo {
    public static void main (String[] args) {
        Cache cache = new Cache();

        //写的时候只有一个线程独占锁 互斥其他
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                cache.write();
            },i+"").start();
        }

        //并发读,读锁只有一把,所有线程共享
        for (int i = 0; i < 200; i++) {
            new Thread(()->{
                cache.read();
            },i+"").start();
        }



    }
}
class Cache{
    ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    public void read() {
        //上读锁
        reentrantReadWriteLock.readLock().lock();

        try {
            System.out.println(Thread.currentThread().getId() + "正在读");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            System.out.println(Thread.currentThread().getId() + "读完");
            reentrantReadWriteLock.readLock().unlock();
        }
    }


    public void write() {
        //上读锁
        reentrantReadWriteLock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getId() + "正在写");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getId() + "睡1s");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值