顺序锁

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对象。当两个线程向两个账户之间互相转账时,这两个线程会按相同的次序对账户进行锁定,这样可以保证只有一个线程完成转账后,另一个线程才能获获取到所有的锁,然后进行转账操作。

读写锁和顺序锁是在多线程编程中用于同步的两种机制。 读写锁(Read-Write Lock)是一种特殊的锁,它允许多个线程同时进行读操作,但只能有一个线程进行写操作。读操作不会互斥,因此多个线程可以同时读取共享数据,这样可以提高并发性能。但当有线程进行写操作时,其他线程无法进行读或写操作,直到写操作完成。 读写锁的工作方式如下: - 当一个线程希望进行读操作时,它会尝试获取读锁。如果没有其他线程持有写锁,则该线程可以获取读锁,并进行读操作。 - 当一个线程希望进行写操作时,它会尝试获取写锁。如果没有其他线程持有读锁或写锁,则该线程可以获取写锁,并进行写操作。 - 当一个线程持有写锁时,其他线程无法获取读锁或写锁。当一个线程持有读锁时,其他线程可以获取读锁,但无法获取写锁。 顺序锁(Sequence Lock)是一种用于解决并发更新数据的同步机制。它允许多个线程同时进行读操作和写操作,并通过一个序列号来确保操作的顺序。每次更新共享数据时,都会增加序列号。当一个线程进行读操作时,会记录当前的序列号。如果在读操作期间,序列号发生变化,则需要重新读取共享数据。 顺序锁的工作方式如下: - 当一个线程希望进行读操作时,它会记录当前的序列号,并读取共享数据。 - 当一个线程希望进行写操作时,它会增加序列号,并更新共享数据。 - 在读操作期间,如果序列号发生变化,则需要重新读取共享数据。 顺序锁适用于读操作频繁而写操作较少的场景,因为它允许多个线程同时进行读操作,避免了读操作的互斥。但需要注意的是,顺序锁可能会导致写操作的延迟,因为在写操作期间,其他线程无法进行读或写操作。 需要根据具体的需求和场景选择适合的同步机制,读写锁和顺序锁都是常用的同步机制之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值