顺序锁

Java自身不能防止死锁也不能对死锁进行检测。当两个或多个线程以不同的顺序请求和释放锁时,就可能会发生死锁。所以程序必须以相同的顺序来请求和释放锁,避免产生死锁。

错误示例(不同的锁次序):

final class BankAccount {
private double balanceAmount; // Total amount in bank account

BankAccount(double balance) {
    this.balanceAmount = balance;
}

// Deposits the amount from this object instance
// to BankAccount instance argument ba
private void depositAmount(BankAccount ba, double amount) {
    synchronized (this) {
        synchronized (ba) {
            if (amount > balanceAmount) {
                throw new IllegalArgumentException("Transfer cannot be completed");
            }
            ba.balanceAmount += amount;
            this.balanceAmount -= amount;
        }
    }
}

public static void initiateTransfer(final BankAccount first, final BankAccount second, final double amount) {

    Thread transfer = new Thread(new Runnable() {
        public void run() {
            first.depositAmount(second, amount);
        }
    });
    transfer.start();
}

public static void main(String[] args) {
    BankAccount bankA = new BankAccount(15000);
    BankAccount bankB = new BankAccount(9000);

    initiateTransfer(bankA, bankB, 500);
    initiateTransfer(bankB, bankA, 1400);
    …
}

}
上面的错误示例中会存在死锁的情况。当bankA\bankB两个银行账户同步互相进行转账时,就可能会导致死锁的问题。

正确示例(顺序锁):

final class BankAccount implements Comparable {
private double balanceAmount; // Total amount in bank account

private final Object lock;

private final long id; // Unique for each BankAccount

private static final AtomicLong nextID = new AtomicLong(0); // Next unused
                                                            // ID

BankAccount(double balance) {
    this.balanceAmount = balance;
    this.lock = new Object();
    this.id = nextID.getAndIncrement();
}

@Override
public int compareTo(BankAccount ba) {
    return (this.id > ba.id) ? 1 : (this.id < ba.id) ? -1 : 0;
}

// Deposits the amount from this object instance
// to BankAccount instance argument ba
public void depositAmount(BankAccount ba, double amount) {
    BankAccount former, latter;
    if (compareTo(ba) < 0) {
        former = this;
        latter = ba;
    }
    else {
        former = ba;
        latter = this;
    }
    synchronized (former) {
        synchronized (latter) {
            if (amount > balanceAmount) {
                throw new IllegalArgumentException("Transfer cannot be completed");
            }
            ba.balanceAmount += amount;
            this.balanceAmount -= amount;
        }
    }
}

public static void initiateTransfer(final BankAccount first, final BankAccount second, final double amount) {

    Thread transfer = new Thread(new Runnable() {
        @Override
        public void run() {
            first.depositAmount(second, amount);
        }
    });
    transfer.start();
}

}
上述正确示例可以确保以相同的顺序获得和释放多个锁。上述代码中BankAccount对象有一致的次序,BankAccount对象实现了Java.lang.Comparable接口,并覆写了compareTo方法。当发生转账时,会对两个BankAccount对象进行排序,会按排序结果顺序锁定两个BankAccount对象。当两个线程向两个账户之间互相转账时,这两个线程会按相同的次序对账户进行锁定,这样可以保证只有一个线程完成转账后,另一个线程才能获获取到所有的锁,然后进行转账操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值