Java并发编程如何防止死锁?

死锁可能是大家都不想遇到的问题,因为一旦程序出现死锁,如果没有外力的话,程序会因为资源竞争一直处于假死状态。

死锁示例代码如下:

<b>public</b> <b>class</b> DeadLockTest {

    <b>public</b> <b>static</b> String OBJECT_1 = <font>"OBJECT_1"</font><font>;
    <b>public</b> <b>static</b> String OBJECT_2 = </font><font>"OBJECT_2"</font><font>;

    <b>public</b> <b>static</b> <b>void</b> main(String[] args) {
        LockA lockA = <b>new</b> LockA();
        <b>new</b> Thread(lockA).start();

        LockB lockB = <b>new</b> LockB();
        <b>new</b> Thread(lockB).start();
    }

}

<b>class</b> LockA implements Runnable {

    @Override
    <b>public</b> <b>void</b> run() {
        <b>synchronized</b> (DeadLockTest.OBJECT_1) {
            <b>try</b> {
                Thread.sleep(500);

                <b>synchronized</b> (DeadLockTest.OBJECT_2) {
                    System.out.println(</font><font>"LockA"</font><font>);
                }
            } <b>catch</b> (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

<b>class</b> LockB implements Runnable {

    @Override
    <b>public</b> <b>void</b> run() {
        <b>synchronized</b> (DeadLockTest.OBJECT_2) {
            <b>try</b> {
                Thread.sleep(500);

                <b>synchronized</b> (DeadLockTest.OBJECT_1) {
                    System.out.println(</font><font>"LockB"</font><font>);
                }
            } <b>catch</b> (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
</font>

当一个线程获得了 OBJECT_1 锁时,它并没有释放锁,然后再申请 OBJECT_2 锁。

这时,另一个线程获取了OBJECT_2锁,并没有释放锁去申请OBJECT_1锁。

由于 OBJECT_1 和 OBJECT_2 锁都没有被释放,所以两个线程会一起请求,陷入死循环,即出现死锁情况。

那么如果避免了死锁问题呢?

# 1. 缩小锁的范围。

死锁情况可能是如上锁范围过大造成的。

那么,解决方案就是缩小锁的范围。

<b>class</b> LockA implements Runnable {

    @Override
    <b>public</b> <b>void</b> run() {
        <b>synchronized</b> (DeadLockTest.OBJECT_1) {
            <b>try</b> {
                Thread.sleep(500);
            } <b>catch</b> (InterruptedException e) {
                e.printStackTrace();
            }
        }
        <b>synchronized</b> (DeadLockTest.OBJECT_2) {
             System.out.println(<font>"LockA"</font><font>);
        }
    }
}

<b>class</b> LockB implements Runnable {

    @Override
    <b>public</b> <b>void</b> run() {
        <b>synchronized</b> (DeadLockTest.OBJECT_2) {
            <b>try</b> {
                Thread.sleep(500);
            } <b>catch</b> (InterruptedException e) {
                e.printStackTrace();
            }
        }
        <b>synchronized</b> (DeadLockTest.OBJECT_1) {
             System.out.println(</font><font>"LockB"</font><font>);
        }
    }
}
</font>

在获取 OBJECT_1 锁的代码块中,不包含获取 OBJECT_2 锁的代码。

同时,获取OBJECT_2锁的代码块中不包含获取OBJECT_1锁的代码。

# 2. 保证锁的顺序。

在死锁的情况下,线程获取锁的顺序是OBJECT_1和OBJECT_2。

另一个线程以相反的顺序获取锁:OBJECT_2 和 OBJECT_1。

那么,如果我们能保证每次获取锁的顺序都是一样的,就不会出现死锁问题。

<b>class</b> LockA implements Runnable {

    @Override
    <b>public</b> <b>void</b> run() {
        <b>synchronized</b> (DeadLockTest.OBJECT_1) {
            <b>try</b> {
                Thread.sleep(500);

                <b>synchronized</b> (DeadLockTest.OBJECT_2) {
                    System.out.println(<font>"LockA"</font><font>);
                }
            } <b>catch</b> (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

<b>class</b> LockB implements Runnable {

    @Override
    <b>public</b> <b>void</b> run() {
        <b>synchronized</b> (DeadLockTest.OBJECT_1) {
            <b>try</b> {
                Thread.sleep(500);

                <b>synchronized</b> (DeadLockTest.OBJECT_2) {
                    System.out.println(</font><font>"LockB"</font><font>);
                }
            } <b>catch</b> (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
</font>

两个线程,每个线程先获取 OBJECT_1 锁,然后再获取 OBJECT_2 锁。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值