线程安全3:死锁与Synchronized

概念的引入

  我们先看一段代码与运行框。

  

package Thread;

public class Synchronized {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("t1使用锁1");

                try {
                    Thread.sleep(100); // 确保线程2能获取到lock2
                } catch (InterruptedException e) {}

                System.out.println("t1 等待 lock 2...");
                synchronized (lock2) {
                    System.out.println("t1获取两个锁!");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("t2使用锁2");

                try {
                    Thread.sleep(100); // 确保线程1能获取到lock1
                } catch (InterruptedException e) {}

                System.out.println("t2: 等待锁1...");
                synchronized (lock1) {
                    System.out.println("t2获取两个锁!");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

  我们可以发现t1 与t2 都无法获取对方先使用的lock1和lock2.这是为什么?明明我们在代码中让线程t1与t2都获取了lock1与lock2,但是代码并没有执行。

原因

Synchronized

  Synchronized是Java中用于实现线程同步的关键字,它提供了一种内置的锁机制,可以确保多个线程安全地访问共享资源,具有三个核心作用---原子性,可见性,有序性。

原子性:确保被保护的代码块或方法作为一个不可分割的单元执行。

可见性:当一个线程释放锁时,它对共享变量的修改对其他线程立即可见。

有序性:防止指令重排序,确保代码按编写顺序执行。

代码解析

线程中:

  线程1获取lock1,线程2获取lock2。

  线程1尝试获取lock2(但被线程2持有)

  线程2尝试获取lock1(但被线程1持有)

  由于Synchronized的作用,代码块无法被分割,且顺序执行。导致了线程1持有lock1等待着lock2,但是线程2不释放lock2.而线程2持有lock2等待lock1,线程1不释放lock1.导致了循环等待。

  死锁的四个必要条件

互斥条件(Mutual Exclusion):资源一次只能被一个线程占用,其他线程必须等待该资源被释放后才能获取.

占有且等待(Hold and Wait):线程已经持有至少一个资源,并且正在等待获取其他被占用的资源。

不可抢占(No Preemption):已分配给线程的资源不能被其他线程强行夺取,必须由持有者显式释放.

循环等待(Circular Wait):存在一个线程等待的循环链,每个线程都在等待下一个线程所占用的资源。

  学过《操作系统》的同学对死锁的概念,我想并不陌生。

怎么避免死锁?

死锁预防

我们只需要打破死锁的四个必要条件的其中之一,就可以避免死锁。比如:我们可以一次性将线程需要的资源在线程创建时就,全部分配给它。

死锁避免

死锁避免(Deadlock Avoidance)是一种动态预防死锁的策略,它通过资源分配策略确保系统永远不会进入不安全状态(即可能导致死锁的状态)。与死锁预防(Deadlock Prevention)不同,死锁避免不会破坏死锁的四个必要条件,而是通过智能的资源分配算法来避免系统进入可能发生死锁的状态。(这是书上的概念。)

  类似的,我们可以通过银行家算法来实现这一过程。

当然,还有一种死锁检测与恢复 ,我们现在就不深入探讨了。以后有机会在进行讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值