lock锁和死锁

简介: lock锁和死锁

Lock 锁是 Java 并发编程中的一种同步机制,它提供了比 synchronized 关键字更灵活和可扩展的锁定操作。Lock 锁相比于 synchronized,具有更多的功能和特性,例如支持公平性、可重入性、超时等待、条件变量等。

Lock 锁的基本用法如下:

Lock lock = new ReentrantLock(); // 实例化一个 Lock 对象
// 在需要同步的代码块中使用 lock() 方法获取锁,并在 finally 中使用 unlock() 方法释放锁
lock.lock();
try {
    // 需要同步的代码逻辑
} finally {
    lock.unlock();
}

Lock 锁通过调用 lock() 方法获取锁对象的锁定,并在使用完共享资源后调用 unlock() 方法释放锁。与 synchronized 不同的是,Lock 锁需要手动地显式获取和释放锁,这种方式提供了更细粒度的控制。

在并发编程中,死锁是一种常见的问题,它发生在两个或多个线程相互等待对方所持有的资源时,导致所有线程无法继续执行的状态。简单来说,就是由于资源竞争和请求顺序不当,使得线程之间陷入了相互等待的循环,从而导致程序无法继续执行。

以下是一个简单的死锁示例:

public class DeadlockExample {
    private static Object lock1 = new Object();
    private static Object lock2 = new Object();
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread 1 acquired lock1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("Thread 1 acquired lock2");
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread 2 acquired lock2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("Thread 2 acquired lock1");
                }
            }
        });
        thread1.start();
        thread2.start();
    }
}

此示例展示了一个可能导致死锁的情况。代码中定义了两个静态对象 lock1lock2 作为同步锁。

main 方法中创建了两个线程 thread1thread2。这两个线程分别尝试获取 lock1lock2 的锁来执行一些操作。

thread1 的逻辑如下:

  1. 首先,它通过使用 synchronized 关键字获取了 lock1 的锁。
  2. 然后,在获取 lock1 后,线程休眠了1秒钟。
  3. 在休眠结束后,它尝试获取 lock2 的锁。
  4. 如果成功获取了 lock2 的锁,它将打印一条消息表示已经获取到 lock2

thread2 的逻辑与 thread1 类似,只是获取锁的顺序相反:

  1. 首先,它通过使用 synchronized 关键字获取了 lock2 的锁。
  2. 然后,在获取 lock2 后,线程休眠了1秒钟。
  3. 在休眠结束后,它尝试获取 lock1 的锁。
  4. 如果成功获取了 lock1 的锁,它将打印一条消息表示已经获取到 lock1

当我们运行这段代码时,可能会发生死锁。死锁的原因是两个线程互相持有对方所需的锁,并且在同时等待对方释放锁,形成了循环等待条件。

例如,如果 thread1 获取了 lock1 的锁,并在等待 lock2 的锁时,thread2 已经获取了 lock2 的锁,并在等待 lock1 的锁,这样就出现了循环等待的情况。

在这种情况下,两个线程都会进入无限等待的状态,无法继续执行,即发生了死锁。

要避免死锁,可以采取以下策略:

  1. 避免使用多个锁对象,尽量使用一个共享的对象进行同步。
  2. 当使用多个锁对象时,按照相同的顺序获取锁,避免出现循环等待的情况。
  3. 使用 tryLock() 方法尝试获取锁并设置超时时间,避免无限等待。
  4. 设计良好的资源管理策略,尽量减少对多个资源的同时请求。
  5. 使用工具来检测和分析死锁问题,例如线程转储、锁的可视化工具等。

死锁是并发编程中需要注意的常见问题,合理的锁策略和资源管理可以有效地避免死锁的发生。


相关文章
|
3月前
|
SQL 关系型数据库 MySQL
MySQL使用行级锁时,并非直接锁定记录,而是锁定涉及的索引。对于表`user_item`,更新语句先锁定非主键索引`idx_1`,再锁定主键索引。若两条更新语句分别按不同顺序锁定这两个索引,可能导致互相等待对方释放锁,引发死锁。解决方案包括先查询待更新记录的主键,再按主键更新,确保一致的锁定顺序。
43 2
|
3月前
|
SQL 关系型数据库 MySQL
临键锁引发的死锁
【8月更文挑战第4天】
40 0
临键锁引发的死锁
|
Java 程序员 API
【Lock锁的使用与原理】
【Lock锁的使用与原理】
183 0
|
Linux API C++
锁、避免死锁等相关
锁、避免死锁等相关
67 0
《锁》有那些?
锁是计算机科学中用于控制对共享资源的访问的一种同步机制。不同种类的锁适用于不同的场景和需求。下面是一些常见的锁的种类及其详细介绍:
72 1
|
存储 算法 安全
辛辛苦苦的劳动成果,如何上把锁?
辛辛苦苦的劳动成果,如何上把锁?
|
Java
各种锁的理解
各种锁的理解
118 0
各种锁的理解
|
安全 Java
多线程详解p18、Lock锁
多线程详解p18、Lock锁
|
生物认证
什么是锁?
什么是锁?
126 0
什么是锁?