`

java锁 两个顺序的同步引起的问题

阅读更多
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,就必须等待前一次操作完成,可能产生性能问题。(这里应该有更好的方法)
分享到:
评论

相关推荐

    支持10000同步锁,Spring Boot,Java

    Java提供了两种主要的同步锁:内置锁(也称为监视器锁,由synchronized关键字实现)和显式锁(java.util.concurrent.locks包下的ReentrantLock类)。内置锁是通过synchronized关键字实现的,它提供了对方法或代码块...

    java-syn.zip_Java syn_Java syn锁_java同步锁syn_java锁 syn_syn同步事务锁

    总结来说,Java中的同步锁是多线程编程中的核心概念,通过合理的同步机制,开发者可以有效地管理共享资源,防止数据不一致性和线程安全问题。理解并熟练运用这些机制,对于编写高效、可靠的多线程程序至关重要。

    java锁详解.pdf

    Java 锁可以分为两大类:synchronized 锁和 ReentrantLock 锁。 一、Synchronized 锁 1. 锁的原理:synchronized 锁是基于对象头的 Mark Word 来实现的。Mark Word 中有一个锁标志位,用于标识对象的锁状态。 2. ...

    java 两个线程相互顺序输出

    标题“java 两个线程相互顺序输出”涉及的问题是如何在多线程环境下控制线程的执行顺序,使得两个线程可以按照特定的顺序交替打印输出。这通常涉及到线程同步和通信的概念。下面将详细解释这些知识点。 1. **线程...

    java 线程同步 信号量控制同步

    关于线程同步,需要牢牢记住的第二点是 “共享”这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。 关于线程同步,需要牢牢记住的第三点是,只有“变量”才需要同步访问...

    彻底理解Java中的各种锁.pdf

    在Java中,ReentrantReadWriteLock类是读写锁的实现,它包含两个锁:读锁(共享锁)和写锁(独占锁)。读锁可以被多个线程同时持有,而写锁是独占的,当写锁被占用时,其他线程既不能获取读锁也不能获取写锁。 5. ...

    java使用datax增量同步代码

    Java 使用 DataX 进行增量同步是大数据领域中常见的数据迁移任务,DataX 是阿里开源的一个强大、高效的数据同步工具,它可以实现不同数据存储之间的数据迁移。本篇将详细讲解如何在 Java 项目中利用 DataX 实现增量...

    Java锁的种类以及区别

    读写锁通常包括两个锁:读锁(`ReadLock`)和写锁(`WriteLock`)。当多个线程进行读操作时,它们可以同时获得读锁;当有一个线程进行写操作时,其他所有线程(无论是读还是写)都必须等待。 **示例:** - `...

    java synchronize 线程同步

    在例子中,`execute()`方法没有被`synchronized`修饰时,两个线程并发调用同一个对象的`execute()`方法,导致输出的数字交错,说明这是异步执行的。而当添加了`synchronized`关键字后,输出的数字按照线程启动的顺序...

    java锁的释放与建立

    首先,Java中的锁主要包括两种类型:内置锁(也称为监视器锁)和显式锁。内置锁是通过`synchronized`关键字实现的,它隐含地在每个对象上都存在。当一个线程进入一个由`synchronized`修饰的方法或代码块时,会自动...

    java程序 两个线程实现学生成绩的读写

    在这个场景下,我们可能创建了两个类,一个是`WriterThread`用于写入成绩,另一个是`ReaderThread`用于读取并显示成绩。 在写入线程(`WriterThread`)中,我们需要一个共享的数据结构来存储成绩,例如一个`HashMap, ...

    Java资源同步Java资源同步Java资源同步

    - **修饰方法**:作用于当前实例加锁,如果两个实例的方法同时被调用则不会发生互斥现象,因为调用和锁定的是两个实例。 - **修饰静态方法**:也就是给当前类加锁,会使得所有实例都具有相同的锁记录。 - **修饰代码...

    Java实现的进程同步与互斥(PV)

    下面是一个简单的Java PV操作示例,模拟了两个线程对一个共享资源(如打印机)的互斥访问: ```java import java.util.concurrent.Semaphore; public class PrintService { private Semaphore printerSemaphore =...

    java 门锁终于被打开了(解决死锁)

    可能包含了模拟两个线程试图进入两个房间(代表两个锁)的场景,通过合理的锁管理来避免死锁。`Java.jpg`可能是配合代码的流程图或者类结构图,帮助理解代码逻辑。 总之,理解并掌握Java中的门锁机制和死锁解决方案...

    Java线程的同步与死锁

    死锁是多线程编程中的一种极端情况,当两个或多个线程互相持有对方所需的锁时,这些线程将永远等待下去,无法继续执行。这是一种典型的僵局状态。 ##### 3.2 产生死锁的必要条件 为了发生死锁,必须满足以下四个...

    顺序表java实现

    这两个类都必须实现接口中定义的所有方法,以确保符合顺序表的操作规范。 在Java中,实现顺序表通常使用数组。`BasicSequentialList`可能使用一个`Object`数组来存储任意类型的数据,而`ThreadSafeSequentialList`...

    Java多线程-避免同步机制带来的死锁问题及用Lock锁解决线程安全问题

    ### Java多线程-避免同步机制带来的死锁问题及用Lock锁解决线程安全问题 #### 死锁 ##### 1. 说明 在多线程编程中,死锁是一种常见的问题,指的是两个或多个线程在执行过程中,因为竞争资源而造成的一种相互等待...

    不死锁的哲学家问题实现 java

    在本实现中,我们将创建两个类型的信号量:一个用于表示筷子,另一个用于控制哲学家可以同时就餐的数量。 1. **筷子信号量**:我们为每根筷子创建一个信号量,当哲学家拿起筷子时,他会调用信号量的`acquire()`方法...

    java同步异步知识

    在软件开发领域,特别是针对并发处理和网络编程时,我们经常会遇到“同步”与“异步”这两个概念。简单来说: - **同步(Synchronous)**:指的是程序按照顺序执行,前一个操作未完成之前,后面的代码不会被执行。...

Global site tag (gtag.js) - Google Analytics