可重入锁:synchronized & ReentrantLock

什么是可重入锁?

可重入锁 又叫 递归锁,指当一个线程已经获得某个锁,可以再次获取锁而不会出现死锁。
什么意思呢?

同一个线程外层函数获得锁之后,内层递归函数也想要获得该锁,那么这个线程可以重复的获取该锁,即上了多把锁。

可重入锁的意义:

同一个线程多次获取锁,而不会出现死锁。

非可重入锁会发生什么情况呢?

当一个线程已经获取了一个锁,那么其内层函数如果也需要获取该锁,就必须等待这个线程释放该锁;但这个线程现在又处于等待该锁又不会释放锁的状态,因此会出现死锁。

而可重入锁,不需要等待自身的线程释放该锁才能再次获取,而是可以在不释放该锁的情况下再次加一把锁。从而避免了死锁的发生。

Synchronized & ReentrantLock

Synchronized 和 ReentrantLock都是可重入锁;Synchronized 是自动获取锁自动释放锁,而ReentrantLock需要手动加锁手动解锁,需要注意,加几层锁就需要释放几层锁。如果加锁多于解锁,程序运行不会报错,但会一直运行不会结束,可能会导致死锁。如果解锁多于加锁,运行时会报错IllegalMonitorStateException。

synchronized案例
public class SynchronizedDemo {
    public static void main(String[] args) {
        Phone phone=new Phone();
        syncTest(phone);
        System.out.println();
    }

    private static void syncTest(Phone phone) {

        new Thread(()->{
            try{
                phone.sendSMS();
            }catch (Exception e){
                e.printStackTrace();
            }
        },"t1").start();

        new Thread(()->{
            try{
                phone.sendSMS();
            }catch (Exception e){
                e.printStackTrace();
            }
        },"t2").start();
    }
}
class Phone implements Runnable{
    //Synchronized TEST
    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getId()+"\t"+Thread.currentThread().getName()+"\t"+"sendSMS()");
        sendEmail();//递归调用
    }
    public synchronized void sendEmail(){
        System.out.println(Thread.currentThread().getId()+"\t"+Thread.currentThread().getName()+"\t"+"sendEmail()");
    }
}

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

t1,t2两个线程都想去获取对象锁phone,当一个t1线程调用了sendSMS()方法先获得锁时,再调用sendEmail()方法,sendEmail()也需要synchronized加锁,由结果可见再次获取锁成功;自动释放锁后,最后再由t2线程获取锁。
由打印结果可知,synchronized是一个可重入锁,每个线程都获取了两次锁。

ReentrantLock案例
public class ReentrantLockDemo {
    public static void main(String[] args) {
        Phone phone=new Phone();
   
        Thread t3=new Thread(phone,"t3");
        Thread t4=new Thread(phone,"t4");
        t3.start();
        t4.start();

    }
}
class Phone implements Runnable{
    //Reentrant TEST
    Lock lock=new ReentrantLock();
    @Override
    public void run() {
        get();
    }
    public void get(){
        lock.lock();
        try{
            System.out.println(Thread.currentThread().getId()+"\t"+Thread.currentThread().getName()+"\t"+"get()");
            set();
        }finally {
            lock.unlock();
        }
    }
    public void set(){
        lock.lock();
        try{
            System.out.println(Thread.currentThread().getId()+"\t"+Thread.currentThread().getName()+"\t"+"set()");
        }finally {
            lock.unlock();
        }
    }
}

运行结果如下:
在这里插入图片描述
同样,创建t3,t4两个线程,调用get()方法,t3线程先获得锁,然后再调用set()方法再次获得锁,再经过两次手动释放锁后,t4线程再获得锁。

由结果可知,ReentrantLock也是一个可重入锁,一个线程可多次获得相同的锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值