JUC并发编程--- 一些锁的理解

Posted 小样5411

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程--- 一些锁的理解相关的知识,希望对你有一定的参考价值。

1、公平锁、非公平锁

公平锁:非常公平,不能插队,先来后到
非公平锁(默认):非常不公平,可以插队
比如:有一个线程需要3s执行结束,另一个3h执行结束,但3h先到。那么对于公平锁,3s必须等3h执行完毕,而对于非公平锁就可以让3s先插队执行。
在这里插入图片描述
如上,默认都是非公平,synchronized 和Lock都是默认非公平

2、可重入锁

可重入锁又称递归锁

假设我们进自己家需要一把大门锁,然后拿到大门锁,自然就可以进房间里面
在这里插入图片描述
代码演示一下

package com.yx.lock;

public class demo01 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sms();
        },"A").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");
    }
}

线程A调用sms方法时,首先会给sms加锁,然后打印sms,进入call中,自动拿到call的锁,并call打印后,最后再释放所有锁,也就是拿到外面的锁就会自动拿到里面的锁,最后执行完所有的内容,释放锁。

这里用的是synchronized ,我们来看看Lock锁对比一下

3、自旋锁

自旋就是循环,加了一个while语句或者do…while语句。我们来自己实现一个自旋锁,然后用它进行加锁解锁

package com.yx.lock;

import java.util.concurrent.atomic.AtomicReference;

//CAS(CompareAndSet)实现自旋锁
public class SpinLockDemo {

    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    //加锁
    public void myLock(){
        Thread thread = Thread.currentThread();//当前线程
        System.out.println(Thread.currentThread().getName()+"->myLock");

        //不成立就一直循环自旋
        while (!atomicReference.compareAndSet(null,thread)){

        }
    }

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

运行下面方法

package com.yx.lock;

import java.util.concurrent.TimeUnit;

public class TestSpinLock {
    public static void main(String[] args) throws InterruptedException {
        SpinLockDemo lock = new SpinLockDemo();

        new Thread(()->{
            lock.myLock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.myUnLock();
            }
        },"T1").start();

        TimeUnit.SECONDS.sleep(1);//保证T1线程先拿到锁
        new Thread(()->{
            lock.myLock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.myUnLock();
            }
        },"T2").start();
    }
}

在这里插入图片描述
分析:首先T1线程拿到锁,进入自旋,然后T2也拿到锁,5秒后T1解锁跳出自旋,T2也跟着解锁。注意这个执行的顺序

以上是关于JUC并发编程--- 一些锁的理解的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

JUC并发编程 活跃性 -- 活锁 & 死锁/活锁的区别 & 饥饿

JUC编程(java.util.concurrent)

秋招之路9:juc并发

并发编程总结5-JUC-REENTRANTLOCK-3(非公平锁)

JUC并发编程 -- synchronized 原理进阶之轻量级锁 & 锁膨胀