深入理解Java中涉及的各种锁

公平锁、非公平锁

一、理解概念
公平锁:非常公平,不允许插队,必须先来后到
非公平锁(系统默认):允许插队,避免一个3秒的线程,等待一个3小时的线程执行完毕才执行

二、设置公平锁的方式

//创建锁的时候,加上一个true就会设置为公平锁
ReentrantLock reentrantLock = new ReentrantLock(true);

乐观锁和悲观锁

       

可重入锁

一、理解
所有的锁,都叫可重入锁,也叫递归锁。拿到了外面的锁,自动就获得了里面的锁

二、测试

//测试可重入锁
public class Test01 {
    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() + "执行了发短信!");
        call();
    }
    public synchronized void call(){
        System.out.println(Thread.currentThread().getName() + "执行了打电话!");
    }
}


控制台:
线程A执行完sms方法,并不会释放锁,反而会进入到call方法中,当call方法执行完毕才真正释放锁,然后B线程才会执行

自旋锁

一、理解自旋锁
自旋锁的底层原理就是一个while循环,如果条件不满足,就会一直处在while循环中出不来,其他的线程也就拿不到对应的锁,不能执行对应的任务,因此就保证了线程的安全
 

二、手写自旋锁

/*自旋锁
* */
public class SpinLock {
    //创建一个原子引用类对象,这样就可以调用CAS方法
    AtomicReference<Thread> atomicReference = new AtomicReference<Thread>();

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

        //自旋锁的关键,如果第一个线程没有释放锁,那么这个while循环一直都是true死循环,不能往下执行业务代码
        while (!atomicReference.compareAndSet(null,thread)){

        }
    }

    //解锁的方法
    public void myUnLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + "-->myUnLock");
        //解锁不需要循环,如果真正走到解锁的步骤,直接痛快的把原子引用类中的thread更新成null,那么其他的线程才可以拿到锁,进行加锁的操作
        atomicReference.compareAndSet(thread,null);
    }
}

三、测试

public class TestSpinLock {
    public static void main(String[] args) throws InterruptedException {
        //创建自定义锁的对象,等价于之前定义的ReentrantLock可重入锁对象
        SpinLock lock = new SpinLock();

        //创建线程A
        new Thread(()->{
            lock.myLock(); //获得锁
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.myUnLock(); //解锁
            }
        },"A").start();

        //模拟延时
        TimeUnit.SECONDS.sleep(3);

        //创建线程B
        new Thread(()->{
            lock.myLock(); //获得锁
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.myUnLock(); //解锁
            }
        },"B").start();
    }
}


控制台:
只有当A线程拿到锁,执行完业务代码,释放锁,B线程才能获得锁,执行他的业务代码,因为线程B可能会在线程A执行的时候想要拿到锁,但是A没释放锁,线程B一直会在得到锁的myLock方法中的while中死循环,即持续自旋

死锁理解和排查死锁

一、理解死锁
互相想读取对方的锁


二、排查死锁现象的方法
1、使用jps -l命令,在idea的Terminal中查看当前存活的进程,定位进程号

2、输入命令jstack + 进程号,查看问题
往下翻提示信息,查看线程的堆栈信息,就能找到死锁问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Be explorer

若认可笔者文章,手头富裕望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值