pet*_*ter 18 java parallel-processing multithreading deadlock
我想知道在以下示例中有哪些替代方法可以避免死锁.以下示例是传输死锁问题的典型银行帐户.在实践中有哪些更好的解决方法?
class Account {
double balance;
int id;
public Account(int id, double balance){
this.balance = balance;
this.id = id;
}
void withdraw(double amount){
balance -= amount;
}
void deposit(double amount){
balance += amount;
}
}
class Main{
public static void main(String [] args){
final Account a = new Account(1,1000);
final Account b = new Account(2,300);
Thread a = new Thread(){
public void run(){
transfer(a,b,200);
}
};
Thread b = new Thread(){
public void run(){
transfer(b,a,300);
}
};
a.start();
b.start();
}
public static void transfer(Account from, Account to, double amount){
synchronized(from){
synchronized(to){
from.withdraw(amount);
to.deposit(amount);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道它是否会解决死锁问题,如果我在我的传输方法中将嵌套锁分开,如下所示
synchronized(from){
from.withdraw(amount);
}
synchronized(to){
to.deposit(amount);
}
Run Code Online (Sandbox Code Playgroud)
Wil*_*ung 28
对帐户进行排序.死锁来自账户的排序(a,b vs b,a).
所以尝试:
public static void transfer(Account from, Account to, double amount){
Account first = from;
Account second = to;
if (first.compareTo(second) < 0) {
// Swap them
first = to;
second = from;
}
synchronized(first){
synchronized(second){
from.withdraw(amount);
to.deposit(amount);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个经典的问题.我看到两种可能的解决方案
除了有序锁定解决方案之外,您还可以通过在执行任何帐户转移之前同步私有静态最终锁定对象来避免死锁.
class Account{
double balance;
int id;
private static final Object lock = new Object();
....
public static void transfer(Account from, Account to, double amount){
synchronized(lock)
{
from.withdraw(amount);
to.deposit(amount);
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案具有以下问题:专用静态锁限制系统"顺序地"执行传输.
如果每个帐户都有一个ReentrantLock,则可以是另一个:
private final Lock lock = new ReentrantLock();
public static void transfer(Account from, Account to, double amount)
{
while(true)
{
if(from.lock.tryLock()){
try {
if (to.lock.tryLock()){
try{
from.withdraw(amount);
to.deposit(amount);
break;
}
finally {
to.lock.unlock();
}
}
}
finally {
from.lock.unlock();
}
int n = number.nextInt(1000);
int TIME = 1000 + n; // 1 second + random delay to prevent livelock
Thread.sleep(TIME);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种方法中不会发生死锁,因为这些锁永远不会被无限期地保留.如果获取了当前对象的锁定但第二个锁定不可用,则释放第一个锁定,并且线程在尝试重新获取锁定之前会休眠一段指定的时间.
小智 5
您还可以为每个帐户创建单独的锁(在 Account 类中),然后在执行事务之前获取两个锁。看一看:
private boolean acquireLocks(Account anotherAccount) {
boolean fromAccountLock = false;
boolean toAccountLock = false;
try {
fromAccountLock = getLock().tryLock();
toAccountLock = anotherAccount.getLock().tryLock();
} finally {
if (!(fromAccountLock && toAccountLock)) {
if (fromAccountLock) {
getLock().unlock();
}
if (toAccountLock) {
anotherAccount.getLock().unlock();
}
}
}
return fromAccountLock && toAccountLock;
}
Run Code Online (Sandbox Code Playgroud)
获得两把锁后,您可以进行转移而无需担心安全。
public static void transfer(Acc from, Acc to, double amount) {
if (from.acquireLocks(to)) {
try {
from.withdraw(amount);
to.deposit(amount);
} finally {
from.getLock().unlock();
to.getLock().unlock();
}
} else {
System.out.println(threadName + " cant get Lock, try again!");
// sleep here for random amount of time and try do it again
transfer(from, to, amount);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9726 次 |
| 最近记录: |