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

来源:互联网 发布:罗志祥女友的淘宝店名 编辑:程序博客网 时间:2024/05/21 11:23

问题重现

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();    }}