ReentrantLock与synchronized的区别

文章讨论了Java中的synchronized关键字和ReentrantLock锁的异同。synchronized提供简单的线程同步,保证原子性,而ReentrantLock则提供更高级的功能,如公平锁和可中断锁,具有更高的灵活性。文章通过代码示例展示了两者的使用,并指出ReentrantLock需要手动管理锁的获取与释放,而synchronized自动处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实现描述

        synchronized 是 Java 中的关键字,它可以用来保证一段代码的原子性,synchronized 是一种比较简单的线程同步方式。在Java中,每个对象都有一个monitor监视器,当一个线程获取了一个对象的monitor时,其他线程就不能再获取该对象的monitor,直到第一个线程释放该对象的monitor。因此,使用synchronized关键字可以保证同一时间只有一个线程执行该对象中的synchronized代码块。

        ReentrantLock 是一个可重入的互斥锁,它与 synchronized 有着类似的功能,但是它提供了更多的灵活性和更高的性能。ReentrantLock 提供了一些高级功能,如公平锁和可中断锁等。

        ReentrantLock锁的实现步骤总结为三点:

        1、未竞争到锁的线程将会被CAS视为一个链表结构并且被挂起。

        2、竞争到锁的线程执行完后释放锁并且将唤醒链表中的下一个节点。

        3、被唤醒的节点将从被挂起的地方继续执行逻辑。

二、代码案例

        synchronized 可用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用在代码块上。

        synchronized 会自动加锁和释放锁,当进入 synchronized 修饰的代码块之后会自动加锁,当离开 synchronized 的代码段之后会自动释放锁。synchronized基础使用:

public class Demo1 {
    public static void main(String[] args) {
        //公共票池,默认数量为20张
        TicketPool ticketPool = new TicketPool(20);
        //创建三个线程,用于模拟三个不同的售票窗口,共同卖出公共票池中的20张门票
        Thread thread1 = new Thread(ticketPool,"窗口1");
        Thread thread2 = new Thread(ticketPool,"窗口2");
        Thread thread3 = new Thread(ticketPool,"窗口3");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}
//票池类(门票数+售票任务)
class TicketPool implements Runnable {
    private int ticketNum;
    public TicketPool(int ticketNum){
        this.ticketNum = ticketNum;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "准备好了,可以开始售票!");
        //线程竞争CPU执行权(this锁)
        synchronized (this){
            while (true){
                if (ticketNum <= 0){
                    System.out.println(Thread.currentThread().getName() + ":不好意思,票卖完了");
                    return;
                }else {
                    System.out.println(Thread.currentThread().getName() + "卖出了1张门票,还剩" + --ticketNum + "张门票");
                    try {
                        //当前线程休眠1000毫秒
                        //注意:休眠过程中,当前线程不会让出”this锁“,此处为引发错误的原因
//                        Thread.sleep(1000);
                        //持有当前this锁的对象进入等待,等待时间1000毫秒
                        this.wait(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}

         而 ReentrantLock 需要手动加锁和释放锁,ReentrantLock的基础使用:

//同步
public class Demo5 {
    public static void main(String[] args) {
        Counter1 counter1 = new Counter1();
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                counter1.add();
            }
        };
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                counter1.dec();
            }
        };
        System.out.println(Counter1.count);
    }
}
//计数器类
class Counter1{
    //用于计数的公共变量
    public static int count = 0;
    //创建锁
    private final ReentrantLock lock = new ReentrantLock();

    //递增
    public void add(){
        for (int i = 0;i <= 10000;i++){
            //加锁
            lock.lock();
            try{
                count += i;
            }finally {
                //释放锁
                lock.unlock();
            }
        }
    }

    //递减
    public void dec(){
        for (int i = 0;i <= 10000;i++){
            //加锁
            lock.lock();
            try{
                count -= i;
            }finally {
                //释放锁
                lock.unlock();
            }
        }
    }
}

 

三、区别

ReentrantLock 和 Synchronized的区别
ReentrantLockSynchroniaed
锁实现机制AQS监视器Monitor
获取锁可以通过tryLock()尝试获取锁,更加灵活线程抢占模型
释放锁必须手动通过unlock()释放锁自动释放
锁类型支持公平锁和非公平锁非公平锁
可重入性可重入可重入
响应中断可响应中断不可响应中断(可能会死锁)

        ReentrantLock构造函数:默认是采用的非公平策略获取锁。 

        ReentrantLock总共有三个内部类:Sync、NonfairSync、FairSync。
        NonfairSync类,表示采用非公平策略获取锁:每一次都尝试获取锁,不会按照公平等待的原则进行等待,不会让等待时间最久的线程获得锁。
        FairSync类,表示采用公平策略获取锁:当资源空闲时,它总是会先判断 sync队列是否有等待时间更长的线程,如果存在,则将当前线程加入到等待队列的尾部,实现了公平获取原则。
        
       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sorenw

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值