b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

多线程死锁是如此简单

电脑杂谈  发布时间:2020-05-02 11:18:27  来源:网络整理

解决线程死锁_多线程如何避免死锁_避免死锁

如果在Java中使用多线程,可能会导致死锁问题. 死锁将使程序始终卡住,不再执行程序. 我们只能通过中止然后重新启动来重新启动程序.

僵局的原因可以概括为三句话:

首先,让我们看一下最简单的死锁(锁定顺序死锁)是如何发生的:

public class LeftRightDeadlock {
    private final Object left = new Object();
    private final Object right = new Object();
    public void leftRight() {
		// 得到left锁
        synchronized (left) {
			// 得到right锁
            synchronized (right) {
                doSomething();
            }
        }
    }
    public void rightLeft() {
		// 得到right锁
        synchronized (right) {
			// 得到left锁
            synchronized (left) {
                doSomethingElse();
            }
        }
    }
}

我们的线程交错执行,那么可能会发生以下情况:

解决线程死锁_避免死锁_多线程如何避免死锁

让我们看看以下示例. 您认为会发生僵局吗?

    // 转账
    public static void transferMoney(Account fromAccount,
                                     Account toAccount,
                                     DollarAmount amount)
            throws InsufficientFundsException {
        // 锁定汇账账户
        synchronized (fromAccount) {
            // 锁定来账账户
            synchronized (toAccount) {
                // 判余额是否大于0
                if (fromAccount.getBalance().compareTo(amount) < 0) {
                    throw new InsufficientFundsException();
                } else {
                    // 汇账账户减钱
                    fromAccount.debit(amount);
                    // 来账账户增钱
                    toAccount.credit(amount);
                }
            }
        }
    }

上面的代码似乎没有问题: 在转移之前锁定两个帐户以确定余额是否足够!

但是,也可能发生死锁:


A:transferMoney(myAccount,yourAccount,10);


B:transferMoney(yourAccount,myAccount,20);

让我们看看以下示例:

public class CooperatingDeadlock {
    // Warning: deadlock-prone!
    class Taxi {
        @GuardedBy(this) private Point location, destination;
        private final Dispatcher dispatcher;
        public Taxi(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }
        public synchronized Point getLocation() {
            return location;
        }
        // setLocation 需要Taxi内置锁
        public synchronized void setLocation(Point location) {
            this.location = location;
            if (location.equals(destination))
                // 调用notifyAvailable()需要Dispatcher内置锁
                dispatcher.notifyAvailable(this);
        }
        public synchronized Point getDestination() {
            return destination;
        }
        public synchronized void setDestination(Point destination) {
            this.destination = destination;
        }
    }
    class Dispatcher {
        @GuardedBy(this) private final Set<Taxi> taxis;
        @GuardedBy(this) private final Set<Taxi> availableTaxis;
        public Dispatcher() {
            taxis = new HashSet<Taxi>();
            availableTaxis = new HashSet<Taxi>();
        }
        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }
        // 调用getImage()需要Dispatcher内置锁
        public synchronized Image getImage() {
            Image image = new Image();
            for (Taxi t : taxis)
                // 调用getLocation()需要Taxi内置锁
                image.drawMarker(t.getLocation());
            return image;
        }
    }
    class Image {
        public void drawMarker(Point p) {
        }
    }
}

多线程如何避免死锁_解决线程死锁_避免死锁

上面的getImage()和setLocation(点位置)都需要获取两个锁

这隐式获取了两个锁(对象之间的协作).

这种方式也很容易导致死锁...

有三种方法可以避免死锁:

上面的transferMoney()死锁的原因是因为锁定顺序不一致〜

然后可以将上面的示例转换如下:

public class InduceLockOrder {
    // 额外的锁、避免两个对象hash值相等的情况(即使很少)
    private static final Object tieLock = new Object();
    public void transferMoney(final Account fromAcct,
                              final Account toAcct,
                              final DollarAmount amount)
            throws InsufficientFundsException {
        class Helper {
            public void transfer() throws InsufficientFundsException {
                if (fromAcct.getBalance().compareTo(amount) < 0)
                    throw new InsufficientFundsException();
                else {
                    fromAcct.debit(amount);
                    toAcct.credit(amount);
                }
            }
        }
        // 得到锁的hash值
        int fromHash = System.identityHashCode(fromAcct);
        int toHash = System.identityHashCode(toAcct);
        // 根据hash值来上锁
        if (fromHash < toHash) {
            synchronized (fromAcct) {
                synchronized (toAcct) {
                    new Helper().transfer();
                }
            }
        } else if (fromHash > toHash) {// 根据hash值来上锁
            synchronized (toAcct) {
                synchronized (fromAcct) {
                    new Helper().transfer();
                }
            }
        } else {// 额外的锁、避免两个对象hash值相等的情况(即使很少)
            synchronized (tieLock) {
                synchronized (fromAcct) {
                    synchronized (toAcct) {
                        new Helper().transfer();
                    }
                }
            }
        }
    }
}

多线程如何避免死锁_解决线程死锁_避免死锁

获取相应的哈希值以固定锁定顺序,这样就不会出现死锁的问题!

在协作对象之间的死锁示例中,主要是因为在调用一个方法时需要保持一个锁多线程如何避免死锁,并且在该方法内部还调用了其他带有锁的方法!


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-196408-1.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...