多线程死锁问题分析和解决[java]

问题重现

public class Deadlock {
    static class Friend {
        private final String name;

        public Friend(String name) {
            this.name = name;
        }

        public String getName() {
            return this.name;
        }

        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s" + "  has bowed to me!%n", this.name, bower.getName());
            bower.bowBack(this);
        }
        // 这里会造成 嵌套 获取 对方的锁
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend zhangsan = new Friend("张三");
        final Friend lisi = new Friend("李四");

        // 线程thread1先获取zhangsan的锁,然后在同步块里嵌套竞争锁lisi的锁
        // 此时已经被线程thread2拥有,而thread2在等待zhangsan的锁
        new Thread(new Runnable() {
            public void run() {
                zhangsan.bow(lisi);
            }
        }).start();

        // 而thread2先获取lisi的锁,然后在同步块里嵌套竞争锁zhangsan的锁
        // 此时已经被线程thread1拥有,而thread1在等待李四的锁
        new Thread(new Runnable() {
            public void run() {
                lisi.bow(zhangsan);
            }
        }).start();
    }
}

解决方式

ReentrantLock

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;
/**
 * 用 reentrantLock解决死锁问题
 * 使用reentrantLock显示锁 和 通过使用synchronized同步代码的方式使用 隐式锁基本上是一样的;
 * (一) 一样的地方
 * 1.同一线程在同一时间 只能拥有一个Lock对象
 * 2.Lock对象,也同样支持wait/notify机制,因为内部可以返回Condition接口对象,具体是Condition newCondition()方法
 * (二) 优势,不同点
 * 1.Lock对象有能力在获取锁的时候返回,而不是阻塞在那里(比如用synchronized),如果对象没有锁可以使用,就会立马返回
 * @author TreeNode
 *
 */
public class Safelock {
    static class Friend {
        private final String name;
        private final Lock lock = new ReentrantLock();

        public Friend(String name) {
            this.name = name;
        }

        public String getName() {
            return this.name;
        }

        public boolean impendingBow(Friend bower) {
            Boolean myLock = false;
            Boolean yourLock = false;
            try {
                // 试着去获取锁,占用着返回false
                myLock = lock.tryLock();
                yourLock = bower.lock.tryLock();
            } finally {
                if (!(myLock && yourLock)) {
                    if (myLock) {
                        lock.unlock();
                    }
                    if (yourLock) {
                        bower.lock.unlock();
                    }
                }
            }
            return myLock && yourLock;
        }

        public void bow(Friend bower) {
            if (impendingBow(bower)) {
                try {
                    System.out.format("%s: %s has" + " bowed to me!%n", this.name, bower.getName());
                    bower.bowBack(this);
                } finally {
                    lock.unlock();
                    bower.lock.unlock();
                }
            } else {
                System.out.format("%s: %s started" + " to bow to me, but saw that"
                        + " I was already bowing to" + " him.%n", this.name, bower.getName());
            }
        }

        public void bowBack(Friend bower) {
            System.out.format("%s: %s has" + " bowed back to me!%n", this.name, bower.getName());
        }
    }

    static class BowLoop implements Runnable {
        private Friend bower;
        private Friend bowee;

        public BowLoop(Friend bower, Friend bowee) {
            this.bower = bower;
            this.bowee = bowee;
        }

        public void run() {
            Random random = new Random();
            for (;;) {
                try {
                    Thread.sleep(random.nextInt(10));
                } catch (InterruptedException e) {
                }
                bowee.bow(bower);
            }
        }
    }

    public static void main(String[] args) {
        final Friend zhangsan = new Friend("张三");
        final Friend lisi = new Friend("李四");
        new Thread(new BowLoop(zhangsan, lisi)).start();
        new Thread(new BowLoop(lisi, zhangsan)).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值