优秀的编程知识分享平台

网站首页 > 技术文章 正文

用代码彻底给大家讲清楚java中的死锁

nanyue 2024-10-07 11:24:46 技术文章 10 ℃

死锁是指两个或多个线程在执行过程中,因互相竞争资源而造成的一种僵局,它们都在等待对方释放资源,导致所有线程都无法继续执行下去。

一个典型的死锁场景包含以下几个要素:

  • 互斥条件:指某个资源同时只能被一个线程占用,如果一个线程已经占用了该资源,其他线程就必须等待。
  • 请求与保持条件:指一个线程在持有某个资源的同时,又请求其他的资源,但是这些资源已经被其他线程占用了。
  • 不可剥夺条件:指某些资源不能被强制性地从占用它的线程中夺取,只能由该线程自己释放。
  • 循环等待条件:指存在一种等待循环链,即若干个线程之间形成一种循环等待关系,每个线程都在等待下一个线程所持有的资源。

下面是一个简单的Java代码示例,演示了死锁的产生:

public class DeadlockExample {
    private static final Object LOCK1 = new Object();
    private static final Object LOCK2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (LOCK1) {
                System.out.println("Thread 1 acquired lock 1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (LOCK2) {
                    System.out.println("Thread 1 acquired lock 2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (LOCK2) {
                System.out.println("Thread 2 acquired lock 2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (LOCK1) {
                    System.out.println("Thread 2 acquired lock 1");
                }
            }
        });

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Execution completed");
    }
}

在上述示例中,我们创建了两个线程thread1和thread2,并分别使用synchronized关键字对LOCK1和LOCK2进行加锁。

当thread1获取到LOCK1后,它会尝试获取LOCK2。但是此时thread2已经获取到了LOCK2并持有着该锁,因此thread1会被阻塞等待thread2释放LOCK2。

与此同时,当thread2获取到LOCK2后,它会尝试获取LOCK1。但是此时thread1已经获取到了LOCK1并持有着该锁,因此thread2会被阻塞等待thread1释放LOCK1。

由于thread1和thread2互相等待对方释放锁,因此它们都无法继续执行下去,形成了死锁。这种情况只能通过外部干预(如中断线程或者释放资源)来解决。

为避免死锁的发生,我们需要尽量避免上述四个要素中的任何一个。具体来说,可以采用以下几种方法:

  • 避免使用多个锁,尽量将同步块的粒度降到最小。
  • 避免持有锁的时间过长,及时释放锁。
  • 避免循环等待,按照固定的顺序获取锁。
  • 避免无限期地等待,设置超时时间或者使用可中断锁。
最近发表
标签列表