• Java进阶篇--可重入锁 & 不可重入锁


    目录

    可重入锁(ReentrantLock):

    不可重入锁(NonReentrantLock):

    总结

    代码示例


    当涉及到线程同步和互斥访问共享资源时,可重入锁和不可重入锁是两种常见的锁机制。

    可重入锁(ReentrantLock):

    • 可重入锁是一种支持重进入的锁机制。重进入是指一个线程在持有锁的情况下,可以再次获取相同的锁而不会被阻塞。
    • 可重入锁实现了Lock接口,提供了比内置锁(synchronized关键字)更多的灵活性和功能。
    • 可重入锁允许一个线程反复获得该锁,避免了死锁的发生,同时也提高了代码的简洁性和可读性。
    • 可重入锁支持公平性设置,使得等待时间最长的线程优先获取锁。

    不可重入锁(NonReentrantLock):

    • 不可重入锁是一种不支持重进入的锁机制。也就是说,当一个线程获得了不可重入锁之后,如果再次尝试获取锁,就会被阻塞,直到当前持有锁的线程释放锁。
    • 不可重入锁在Java中没有内置的实现,需要通过自定义实现或基于AQS(AbstractQueuedSynchronizer)等基础类来构建。
    • 不可重入锁可能会导致死锁问题,因为如果一个线程在持有锁的情况下又尝试获取同一个锁,就会导致自己无限等待。

    总结

    可重入锁允许同一线程多次获得锁,而不可重入锁则不支持同一个线程多次获得锁。在大多数情况下,可重入锁是更常用和推荐的选择,因为它提供了更多的功能、灵活性和安全性,同时避免了死锁问题。但在某些特殊情况下,不可重入锁也可能有其应用场景,例如需要强制确保某段代码只能被一个线程执行。

    代码示例

    以下是一个将可重入锁(ReentrantLock)和不可重入锁(NonReentrantLock)结合在一起的代码示例,

    1. import java.util.concurrent.locks.ReentrantLock;
    2. public class main {
    3. private static ReentrantLock reentrantLock = new ReentrantLock(); // 创建可重入锁对象
    4. private static NonReentrantLock nonReentrantLock = new NonReentrantLock(); // 创建不可重入锁对象
    5. public static void main(String[] args) {
    6. Thread thread1 = new Thread(new ReentrantTask());
    7. Thread thread2 = new Thread(new NonReentrantTask());
    8. thread1.start();
    9. thread2.start();
    10. }
    11. static class ReentrantTask implements Runnable {
    12. @Override
    13. public void run() {
    14. reentrantLock.lock(); // 获取可重入锁
    15. try {
    16. System.out.println(Thread.currentThread().getName() + "进入可重入锁临界区");
    17. criticalSectionWithReentrantLock();
    18. System.out.println(Thread.currentThread().getName() + "离开可重入锁临界区");
    19. } finally {
    20. reentrantLock.unlock(); // 释放可重入锁
    21. }
    22. }
    23. private void criticalSectionWithReentrantLock() {
    24. reentrantLock.lock(); // 可重入锁允许同一线程多次获得锁
    25. try {
    26. // 在可重入锁临界区域执行需要同步的操作
    27. System.out.println(Thread.currentThread().getName() + "正在执行可重入锁临界区操作");
    28. } finally {
    29. reentrantLock.unlock(); // 释放可重入锁
    30. }
    31. }
    32. }
    33. static class NonReentrantTask implements Runnable {
    34. @Override
    35. public void run() {
    36. nonReentrantLock.lock(); // 获取不可重入锁
    37. try {
    38. System.out.println(Thread.currentThread().getName() + "进入不可重入锁临界区");
    39. criticalSectionWithNonReentrantLock();
    40. System.out.println(Thread.currentThread().getName() + "离开不可重入锁临界区");
    41. } finally {
    42. nonReentrantLock.unlock(); // 释放不可重入锁
    43. }
    44. }
    45. private void criticalSectionWithNonReentrantLock() {
    46. nonReentrantLock.lock(); // 不可重入锁不允许同一线程多次获得锁
    47. try {
    48. // 在不可重入锁临界区域执行需要同步的操作
    49. System.out.println(Thread.currentThread().getName() + "正在执行不可重入锁临界区操作");
    50. } finally {
    51. nonReentrantLock.unlock(); // 释放不可重入锁
    52. }
    53. }
    54. }
    55. static class NonReentrantLock {
    56. private boolean isLocked = false;
    57. public synchronized void lock() {
    58. while (isLocked) {
    59. try {
    60. wait(); // 等待直到当前线程获取锁
    61. } catch (InterruptedException e) {
    62. Thread.currentThread().interrupt();
    63. }
    64. }
    65. isLocked = true;
    66. }
    67. public synchronized void unlock() {
    68. isLocked = false;
    69. notify(); // 唤醒等待的线程
    70. }
    71. }
    72. }

    在这个示例中,我们创建了一个可重入锁对象 reentrantLock 和一个不可重入锁对象 nonReentrantLock ,并在 ReentrantTask 和 NonReentrantTask 类中分别使用这两种类型的锁来实现线程同步。

    ReentrantTask 类使用可重入锁,在 run() 方法中获取可重入锁并进入临界区域执行操作,而且可以在临界区域内再次获得相同的锁。这展示了可重入锁的特性。
    NonReentrantTask 类使用不可重入锁,在 run() 方法中获取不可重入锁并进入临界区域执行操作,但是如果尝试再次获取相同的锁,将被阻塞。这展示了不可重入锁的特性。
    注意,不可重入锁 NonReentrantLock 是通过自定义类实现的。它使用一个布尔变量 isLocked 来表示当前锁是否被占用,并在 lock() 和 unlock() 方法中使用 synchronized 关键字和 wait()、notify() 方法实现线程同步。

    请注意,混合使用可重入锁和不可重入锁可能需要谨慎处理,以避免死锁和其它线程同步问题。

  • 相关阅读:
    代码随想录 Day - 48|#198 打家劫舍|#213 打家劫舍 II|#337 打家劫舍 III
    10道高频Vuex面试题快问快答
    uniapp h5 MD5加密
    JVM原理:JVM运行时内存模型(通俗易懂)
    4、MySql 索引浅解
    Unity3D工程作为库内嵌到安卓原生开发指南
    快速打造安全的车联网平台
    【LeetCode】1668. 最大重复子字符串
    u盘打不开常见原因|数据恢复方法|解决方案
    Windows服务器部署SpringBoot及文件服务器MinIO
  • 原文地址:https://blog.csdn.net/m0_74293254/article/details/133851040