Java当中的锁的世界

时间:2024年08月20日

作者:小蒋聊技术

邮箱:wei_wei10@163.com

微信:wei_wei10

音频地址:https://xima.tv/1_YcrfVT?_sonic=0

希望大家帮个忙!如果大家有工作机会,希望帮小蒋内推一下,小蒋希望遇到一个认真做事的团队,一起努力。需要简历可以加我微信。

大家好,欢迎来到小蒋聊技术,小蒋准备和大家一起聊聊技术的那些事。

今天小蒋准备和大家一起聊的这个技术就厉害了!那就是Java中的锁!


引言:锁的世界

欢迎大家来到“小蒋了解技术”频道!今天我们来聊聊Java中的锁,锁是什么?简单来说,锁就像是你家门上的锁,防止陌生人进入,让你家里的东西不被乱动。在程序中,锁同样有这个作用,它用来控制对共享资源的访问,确保多线程环境下数据的一致性和安全性。


synchronizedJava的老朋友

介绍

首先,我们来聊聊 synchronized,这是Java中的经典锁。你可以把它想象成一把传统的门锁,只要你手里握着它,别人就不能打开这扇门。synchronized 是Java内置的同步机制,可以用在方法或者代码块上,确保同一时间只有一个线程可以进入同步区域。

底层原理

synchronized 的底层是通过 monitor 实现的。当一个线程访问同步代码块时,它需要获取对象的 monitor,进入临界区;当线程完成操作后,它会释放 monitor,允许其他线程访问。

案例:银行账户转账

让我们通过一个经典的银行账户转账的例子来了解 synchronized 的作用:

public class BankAccount {

    private int balance = 0;



    public synchronized void deposit(int amount) {

        balance += amount;

    }



    public synchronized void withdraw(int amount) {

        if (balance >= amount) {

            balance -= amount;

        }

    }

}

在这个例子中,deposit 和 withdraw 方法使用了 synchronized 关键字,确保了同一时间只有一个线程可以修改账户余额,从而避免了数据不一致的问题。

注意点

  • 性能开销:synchronized 的性能开销较大,因为每次获取和释放锁都会涉及到操作系统的上下文切换。
  • 死锁风险:如果在多个方法中使用 synchronized,可能会出现死锁情况,比如两个线程互相等待对方持有的锁。

ReentrantLocksynchronized的升级版

介绍

接下来,我们来看 ReentrantLock,这是 synchronized 的升级版。你可以把它想象成一把智能门锁,除了能锁门,它还有额外的功能,比如你可以设定锁的公平性,或者允许中断。

底层原理

ReentrantLock 通过 AbstractQueuedSynchronizer (AQS) 实现,AQS 管理了一个同步队列,线程在获取锁时,会被添加到这个队列中,直到锁可用为止。

案例:餐厅排队系统

想象一下你在餐厅排队,ReentrantLock 就像是一个公平的排队系统,确保大家按照顺序用餐。代码如下:

import java.util.concurrent.locks.ReentrantLock;



public class Restaurant {

    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁



    public void eat() {

        lock.lock();

        try {

            // 吃饭逻辑

        } finally {

            lock.unlock();

        }

    }

}

注意点

  • 手动释放锁:与 synchronized 不同,ReentrantLock 需要手动释放锁,如果忘记释放,可能导致死锁。
  • 性能问题:虽然 ReentrantLock 提供了更多功能,但相对来说,它的性能开销也可能更大。

ReadWriteLock:读多写少的神器

介绍

如果你的应用中读取操作远远多于写入操作,ReadWriteLock 是个不错的选择。它允许多个线程同时读取,但在写入时只能有一个线程访问。

底层原理

ReadWriteLock 通过分离读锁和写锁来提高性能。读锁是共享的,而写锁是排他性的。

案例:图书馆借书系统

想象一下图书馆的借书系统。很多人可以同时查阅书籍,但每次只有一个人可以借走一本书。代码如下:

import java.util.concurrent.locks.ReentrantReadWriteLock;



public class Library {

    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    private int booksAvailable = 100;



    public void borrowBook() {

        rwLock.writeLock().lock();

        try {

            // 借书逻辑

            booksAvailable--;

        } finally {

            rwLock.writeLock().unlock();

        }

    }



    public void readBooks() {

        rwLock.readLock().lock();

        try {

            // 查阅书籍逻辑

        } finally {

            rwLock.readLock().unlock();

        }

    }

}

注意点

  • 公平性问题:ReadWriteLock 可以是公平的,也可以是不公平的,根据使用场景来决定。
  • 读锁饥饿:如果写锁长时间持有,读锁可能会出现饥饿现象。

StampedLock:高效的读写锁

介绍

最后,我们来看 StampedLock。它比 ReadWriteLock 更高效,特别是在读操作远远多于写操作的情况下。

底层原理

StampedLock 使用时间戳来管理锁的状态,提供了优化的读锁和写锁机制。

案例:停车场

假设你在一个停车场,停车位的状态需要频繁检查,但只有在特殊情况下才需要调整停车位的状态。代码如下:

import java.util.concurrent.locks.ReentrantReadWriteLock;



public class Library {

    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    private int booksAvailable = 100;



    public void borrowBook() {

        rwLock.writeLock().lock();

        try {

            // 借书逻辑

            booksAvailable--;

        } finally {

            rwLock.writeLock().unlock();

        }

    }



    public void readBooks() {

        rwLock.readLock().lock();

        try {

            // 查阅书籍逻辑

        } finally {

            rwLock.readLock().unlock();

        }

    }

}

注意点

  • 写锁性能:虽然读操作性能优越,但写操作的性能可能不如 ReentrantLock。
  • 锁的升级和降级:StampedLock 允许锁的升级和降级,但这需要小心使用,以避免复杂的错误。

总结

锁的选择

  • synchronized:适用于简单的同步需求,易于使用,但性能开销较大,可能导致死锁风险。
  • ReentrantLock:提供了比 synchronized 更灵活的功能,比如公平性和可中断性,适合复杂的同步需求。
  • ReadWriteLock:适用于读多写少的场景,通过分离读锁和写锁提升性能。
  • StampedLock:提供了高效的读写锁机制,特别适合读操作远多于写操作的场景,但写操作性能可能略逊色。

今天我们聊了Java中的几种锁机制:synchronized、ReentrantLock、ReadWriteLock 和 StampedLock。每种锁都有其特点和适用场景,选择合适的锁可以让你的程序在并发环境中更加高效和安全。希望大家在实际开发中能灵活运用这些知识,提升代码质量!

今天小蒋先和大家聊这么多,我们下次再聊!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小蒋聊技术

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

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

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

打赏作者

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

抵扣说明:

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

余额充值