java中存在对多个对象加锁的情况,例如: 在银行系统转账时,需要锁定两个账户,这个时候,顺序使用两个synchronized可能存在死锁的情况,在网上搜索到下面的例子:
Java代码
1.public class Bank {
2. final static Object obj_lock = new Object();
3.
4. // Deadlock crisis
5. public void transferMoney(Account from, Account to, int number) {
6. synchronized (from) {
7. synchronized (to) {
8. from.debit();
9. to.credit();
10. }
11. }
12. }
13.
14. // Thread safe
15. public void transferMoney2(final Account from, final Account to, int number) {
16. class Help {
17. void transferMoney2() {
18. from.debit();
19. to.credit();
20. }
21. }
22.
23. int fromHash = from.hashCode();
24. int toHash = to.hashCode();
25. if (fromHash < toHash) {
26. synchronized (from) {
27. synchronized (to) {
28. new Help().transferMoney2();
29. }
30. }
31. } else if (toHash < fromHash) {
32. synchronized (to) {
33. synchronized (from) {
34. new Help().transferMoney2();
35. }
36. }
37. } else {
38. synchronized (obj_lock) {
39. synchronized (to) {
40. synchronized (from) {
41. new Help().transferMoney2();
42. }
43. }
44. }
45. }
46. }
47.}
public class Bank {
final static Object obj_lock = new Object();
// Deadlock crisis
public void transferMoney(Account from, Account to, int number) {
synchronized (from) {
synchronized (to) {
from.debit();
to.credit();
}
}
}
// Thread safe
public void transferMoney2(final Account from, final Account to, int number) {
class Help {
void transferMoney2() {
from.debit();
to.credit();
}
}
int fromHash = from.hashCode();
int toHash = to.hashCode();
if (fromHash < toHash) {
synchronized (from) {
synchronized (to) {
new Help().transferMoney2();
}
}
} else if (toHash < fromHash) {
synchronized (to) {
synchronized (from) {
new Help().transferMoney2();
}
}
} else {
synchronized (obj_lock) {
synchronized (to) {
synchronized (from) {
new Help().transferMoney2();
}
}
}
}
}
}
若操作账户A,B:
1 A的hashCode小于B, 先锁A再锁B
2 B的hashCode小于A, 先锁B再锁A
3 产生的hashCode相等,先锁住一个全局静态变量,在锁A,B
这样就避免了两个线程分别操作账户A,B和B,A而产生死锁的情况。
注意点:
1 需要为Account对象写一个好的hashCode算法,使得不同账户间产生的hashCode尽量不同。
2 如果某次产生hashCode相同锁住obj_lock,那么如果有新的操作再次产生相同hashCode,就必须等待前一次操作完成,可能产生性能问题。(这里应该有更好的方法)
分享到:
相关推荐
Java提供了两种主要的同步锁:内置锁(也称为监视器锁,由synchronized关键字实现)和显式锁(java.util.concurrent.locks包下的ReentrantLock类)。内置锁是通过synchronized关键字实现的,它提供了对方法或代码块...
总结来说,Java中的同步锁是多线程编程中的核心概念,通过合理的同步机制,开发者可以有效地管理共享资源,防止数据不一致性和线程安全问题。理解并熟练运用这些机制,对于编写高效、可靠的多线程程序至关重要。
Java 锁可以分为两大类:synchronized 锁和 ReentrantLock 锁。 一、Synchronized 锁 1. 锁的原理:synchronized 锁是基于对象头的 Mark Word 来实现的。Mark Word 中有一个锁标志位,用于标识对象的锁状态。 2. ...
标题“java 两个线程相互顺序输出”涉及的问题是如何在多线程环境下控制线程的执行顺序,使得两个线程可以按照特定的顺序交替打印输出。这通常涉及到线程同步和通信的概念。下面将详细解释这些知识点。 1. **线程...
关于线程同步,需要牢牢记住的第二点是 “共享”这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。 关于线程同步,需要牢牢记住的第三点是,只有“变量”才需要同步访问...
在Java中,ReentrantReadWriteLock类是读写锁的实现,它包含两个锁:读锁(共享锁)和写锁(独占锁)。读锁可以被多个线程同时持有,而写锁是独占的,当写锁被占用时,其他线程既不能获取读锁也不能获取写锁。 5. ...
Java 使用 DataX 进行增量同步是大数据领域中常见的数据迁移任务,DataX 是阿里开源的一个强大、高效的数据同步工具,它可以实现不同数据存储之间的数据迁移。本篇将详细讲解如何在 Java 项目中利用 DataX 实现增量...
读写锁通常包括两个锁:读锁(`ReadLock`)和写锁(`WriteLock`)。当多个线程进行读操作时,它们可以同时获得读锁;当有一个线程进行写操作时,其他所有线程(无论是读还是写)都必须等待。 **示例:** - `...
在例子中,`execute()`方法没有被`synchronized`修饰时,两个线程并发调用同一个对象的`execute()`方法,导致输出的数字交错,说明这是异步执行的。而当添加了`synchronized`关键字后,输出的数字按照线程启动的顺序...
首先,Java中的锁主要包括两种类型:内置锁(也称为监视器锁)和显式锁。内置锁是通过`synchronized`关键字实现的,它隐含地在每个对象上都存在。当一个线程进入一个由`synchronized`修饰的方法或代码块时,会自动...
在这个场景下,我们可能创建了两个类,一个是`WriterThread`用于写入成绩,另一个是`ReaderThread`用于读取并显示成绩。 在写入线程(`WriterThread`)中,我们需要一个共享的数据结构来存储成绩,例如一个`HashMap, ...
- **修饰方法**:作用于当前实例加锁,如果两个实例的方法同时被调用则不会发生互斥现象,因为调用和锁定的是两个实例。 - **修饰静态方法**:也就是给当前类加锁,会使得所有实例都具有相同的锁记录。 - **修饰代码...
下面是一个简单的Java PV操作示例,模拟了两个线程对一个共享资源(如打印机)的互斥访问: ```java import java.util.concurrent.Semaphore; public class PrintService { private Semaphore printerSemaphore =...
可能包含了模拟两个线程试图进入两个房间(代表两个锁)的场景,通过合理的锁管理来避免死锁。`Java.jpg`可能是配合代码的流程图或者类结构图,帮助理解代码逻辑。 总之,理解并掌握Java中的门锁机制和死锁解决方案...
死锁是多线程编程中的一种极端情况,当两个或多个线程互相持有对方所需的锁时,这些线程将永远等待下去,无法继续执行。这是一种典型的僵局状态。 ##### 3.2 产生死锁的必要条件 为了发生死锁,必须满足以下四个...
这两个类都必须实现接口中定义的所有方法,以确保符合顺序表的操作规范。 在Java中,实现顺序表通常使用数组。`BasicSequentialList`可能使用一个`Object`数组来存储任意类型的数据,而`ThreadSafeSequentialList`...
### Java多线程-避免同步机制带来的死锁问题及用Lock锁解决线程安全问题 #### 死锁 ##### 1. 说明 在多线程编程中,死锁是一种常见的问题,指的是两个或多个线程在执行过程中,因为竞争资源而造成的一种相互等待...
在本实现中,我们将创建两个类型的信号量:一个用于表示筷子,另一个用于控制哲学家可以同时就餐的数量。 1. **筷子信号量**:我们为每根筷子创建一个信号量,当哲学家拿起筷子时,他会调用信号量的`acquire()`方法...
在软件开发领域,特别是针对并发处理和网络编程时,我们经常会遇到“同步”与“异步”这两个概念。简单来说: - **同步(Synchronous)**:指的是程序按照顺序执行,前一个操作未完成之前,后面的代码不会被执行。...