0 0

关于一个转账死锁的问题0

public class Operation1 {

	private final Object lock = new Object();

	public void transferMoney(final Account fromAccount,
			final Account toAccount, final float dollar) {

		class Helper {
			public void transfer() {
				if (fromAccount.getBalance().compareTo(dollar) < 0) {
					throw new IllegalArgumentException();
				} else {
					fromAccount.setBalance(fromAccount.getBalance() - dollar);
					toAccount.setBalance(toAccount.getBalance() + dollar);
				}
			}
		}

		int fromHashCode = System.identityHashCode(fromAccount);
		int toHashCode = System.identityHashCode(toAccount);

		if (fromHashCode < toHashCode) {
			synchronized (fromAccount) {
				synchronized (toAccount) {
					new Helper().transfer();
				}
			}
		} else if (fromHashCode > toHashCode) {

			synchronized (toAccount) {
				synchronized (fromAccount) {
					new Helper().transfer();
				}
			}
		} else {
			synchronized (lock) {
				synchronized (fromAccount) {
					synchronized (toAccount) {
						new Helper().transfer();
					}
				}
			}
		}

	}

	public static void main(String[] args) {
		final Operation1 o = new Operation1();
		final Account fromAccount = new Account();
		fromAccount.setAccoutName("JetWang");
		fromAccount.setBalance(120000);

		final Account toAccount = new Account();
		toAccount.setAccoutName("china bank");
		toAccount.setBalance(3000);

		new Thread() {
			public void run() {
				o.transferMoney(fromAccount, toAccount, 2000);

			}
		}.start();

		new Thread() {
			public void run() {
				o.transferMoney(toAccount, fromAccount, 1000);

			}
		}.start();
	}

}



背景:如果2个账号同时转账,一个从账号A-B账号,另一个从B账号-A账号
这样就产生了死锁问题。

这一段代码来自于<<java并发编程实践>>中为了解决动态锁顺序死锁。
其中用到了System.identityHashCode方法,我的问题是:
如果这就是一个真实的case,我想问问,通过这种方式能解决死锁正确吗?
怎么感觉很怪,尤其是2个if语句。不太理解他这样做是解决了死锁,但是好像代码跟真实的场景不符合,为什么通过hashcode的大小来决定加锁顺序?,如果是真实的CASE我们该怎么来解决这个次序问题。
2012年10月15日 14:12

2个答案 按时间排序 按投票排序

0 0

死锁产生: 锁获取是环  只要解决这个环即可
线程1: 锁A    锁B
线程2:      锁B    锁A



        //此处其实有问题  如果我调用时是多次new的账户 也可能发生死锁
        int fromHashCode = System.identityHashCode(fromAccount);  
        int toHashCode = System.identityHashCode(toAccount); 

        //可以改成 id 这样就没有问题
 
        if (fromHashCode < toHashCode) {    //如果from账户uuid<end账户uuid
            synchronized (fromAccount) {      //此时先获取from的锁
                synchronized (toAccount) {     //再获取end的锁  即不管从from->end 还是从end转到from 获取锁的顺序固定 不会产生环
                    new Helper().transfer(); 
                } 
            } 
        } else if (fromHashCode > toHashCode) { 
 
            synchronized (toAccount) { 
                synchronized (fromAccount) { 
                    new Helper().transfer(); 
                } 
            } 
        } else { 
            synchronized (lock) { 
                synchronized (fromAccount) { 
                    synchronized (toAccount) { 
                        new Helper().transfer(); 
                    } 
                } 
            } 
        } 

2012年10月15日 21:09
0 0

随便模拟一个长久就可以看出来解过了。

A:HASH33
B:HASH66

CASE1
A->B 50
因为HASH(A)<HASH(B)
synchronized (A)
  synchronized (B)

CASE2
B->A 100
因为HASH(B)>HASH(A)
synchronized (A)
  synchronized (B)

感觉作者的主要目地是,如果CASE1CASE2同时发生,都会先锁HASH值小的那个USER,所以不会死锁,当HASH值一样,例如自己给自己转,就用一个公共的OBJECT锁住。

2012年10月15日 15:54

相关推荐

    操作系统经典同步问题和死锁问题.zip

    例如,试题可能会要求设计一个安全的银行转账系统,或者解决多个打印机共享纸张的问题,这些都是实际操作系统中可能遇到的问题。 解决这些问题的方法通常涉及各种同步原语,如信号量、条件变量、互斥锁等。学习这些...

    java多线程模拟处理银行的实时转账交易

    在本项目中,每个转账操作可能被设计为一个独立的线程,这样可以同时处理多个转账请求,提高系统吞吐量。 接着,要实现银行转账功能,我们需要定义一个`Account`类来表示银行账户,包含账户ID、余额等属性,并提供...

    操作系统死锁检测与解除

    为了检测死锁,Java提供了一个内置的诊断工具——`jstack`,它可以帮助开发者查看线程堆栈信息,找出可能存在的死锁状态。通过分析`jstack`输出,我们可以找到那些处于"等待持有锁"状态的线程,如果发现有循环等待的...

    oracle事务与死锁

    例如,当执行一个转账操作时,通常需要减少一个账户的现金余额,同时增加另一个账户的现金余额。这两个操作要么全部成功以完成转账,要么全部失败以防止数据不一致。 事务控制主要涉及三个命令: 1. `COMMIT`:用于...

    Python中死锁的形成示例及死锁情况的防止

    在Python编程中,多线程环境下的死锁问题是一个常见的复杂性挑战,尤其是在处理并发操作时。死锁发生时,两个或更多的线程彼此等待对方释放资源,导致它们都无法继续执行。了解死锁的形成原因以及如何预防是确保程序...

    java中常见的死锁以及解决方法代码

    在 Java 中,死锁是一个常见的问题,它可能会导致程序的崩溃或卡顿。死锁是指两个或多个线程在等待对方释放资源的过程中,导致所有线程都无法继续执行下去的情况。在 Java 中,我们常使用加锁机制来确保线程安全,...

    MySql示例3:使用事务进行转账.zip

    事务是一组数据库操作,这些操作被视为一个整体,只有当所有操作都成功时,事务才被提交;如果有任何一部分失败,整个事务都会被回滚,以保持数据库的一致性。事务具有四大特性,即原子性(Atomicity)、一致性...

    详解java中产生死锁的原因及如何避免

    java中的死锁是一个常见的问题,它会导致程序的崩溃甚至是系统的崩溃。因此,了解java中产生死锁的原因和如何避免是非常重要的。 java中产生死锁的原因 在java中,死锁是指两个或多个线程之间由于锁的原因而相互...

    第三次作业答案1

    管程通过集中管理临界区,确保一次只有一个进程能访问共享资源,从而避免了并发访问引发的问题。 2. **进程同步与互斥** 并发进程之间的关系可以分为同步和互斥。互斥是指当多个进程竞争同一资源时,一次仅允许一...

    Spring之银行转账案例(七)

    在这个阶段,我们首先创建一个简单的银行转账场景,包括两个账户和一个转账操作。在不考虑事务的情况下,转账可能会导致数据不一致,比如当从一个账户扣款成功,但向另一个账户存款失败时。为了演示这个问题,我们会...

    Beautiful concurrency

    假设我们需要编写一个转账程序,该程序需要在两个账户之间转移资金,同时确保在一个并发环境中,即使有多个线程同时调用转账功能,也不会出现资金未同步更新的情况。即不会出现资金已经从一个账户中扣除,但还未到达...

    关于CoreJava同步的疑惑例子

    - `TransferRunnable.java`可能包含一个实现了`Runnable`接口的类,这个类代表转账任务。在`run()`方法中,它可能调用`Bank`类的转账方法,执行实际的转账操作。 - `SynchBankTest.java`是测试类,创建多个线程...

    linux C 语言模拟哲学家就餐问题

    在操作系统领域,"哲学家就餐问题"是一个经典的多线程同步问题,由计算机科学家Edsger Dijkstra提出。这个问题描述了五个哲学家围坐在一张圆桌旁,每个人面前都有一只筷子。他们交替思考(需要两支筷子)和吃饭。...

    chaptor18.zip

    在生产者-消费者模式中,一个线程将数据放入队列(生产),另一个线程从队列中取出数据(消费)。 - 使用同步队列可以避免阻塞,提高系统效率。例如,小球案例可能用同步队列来模拟球的传递,每个线程代表一个处理...

    ORACLE数据库系统加锁问题的研究.pdf

    为避免死锁,Oracle数据库管理系统会进行死锁检测,一旦检测到死锁,会回滚其中一个事务,解除死锁状态,保证系统的正常运行。 在设计数据库应用程序时,尤其是在并发环境下,必须考虑数据一致性。开发者需要根据...

    操作系统线程同步机制

    Mutex对象提供了一种独占的访问方式,当一个线程进入临界区(转账操作部分)时,会锁定Mutex,其他试图进入的线程会被阻塞,直到Mutex解锁。这样确保了在任何时候只有一个线程可以执行转账操作,保证了数据的一致性。 ...

    临界区自动锁共1页.pdf.zip

    临界区自动锁是计算机多线程编程中的一个重要概念,用于保护共享资源免受并发访问带来的数据不一致性和竞态条件。在这个主题中,我们将深入探讨临界区、互斥锁以及它们在确保线程安全方面的作用。 首先,临界区...

    天津科技大学--数据库系统试卷(A)及答案.doc

    事务的一致性是指事务执行后必须使数据库从一个一致性状态转变到另一个一致性状态。具体来说,事务完成时,数据库中的所有数据都必须符合业务规则的要求,即使事务包含的操作复杂且涉及多个步骤,最终结果也必须是...

Global site tag (gtag.js) - Google Analytics