Java 围绕参数值的同步方法
Java synchronized method around parameter value
考虑以下方法:
public void upsert(int customerId, int somethingElse) {
// some code which is prone to race conditions
}
我想保护此方法免受竞争条件的影响,但这只有在具有相同 customerId
的两个线程同时调用它时才会发生。如果我使整个方法 synchronized
,它会降低效率并且它不是真正需要的。我真正想要的是围绕 customerId
同步它。 Java 是否有可能以某种方式实现?是否有任何内置工具,或者我需要 Map
of Integers
用作锁?
如果您认为我在这里做错了什么,也请随时提出建议:)
谢谢!
您正在寻找的概念称为分段锁定 或条带锁定。为每个客户单独配一把锁太浪费了(锁是相当重量级的)。相反,您希望将您的客户 ID 分区 space 分成合理数量的分区,以匹配所需的并行度。通常 8-16 就足够了,但这取决于方法所做的工作量。
这里概述了一个简单的方法:
private final Object[] locks = new Object[8];
synchronized (locks[customerId % locks.length]) {
...implementation...
}
private static final Set<Integer> lockedIds = new HashSet<>();
private void lock(Integer id) throws InterruptedException {
synchronized (lockedIds) {
while (!lockedIds.add(id)) {
lockedIds.wait();
}
}
}
private void unlock(Integer id) {
synchronized (lockedIds) {
lockedIds.remove(id);
lockedIds.notifyAll();
}
}
public void upsert(int customerId) throws InterruptedException {
try {
lock(customerId);
//Put your code here.
//For different ids it is executed in parallel.
//For equal ids it is executed synchronously.
} finally {
unlock(customerId);
}
}
- id 不仅可以是 'Integer',还可以是任何 class 并正确覆盖 'equals' 和 'hashCode' 方法。
- try-finally - 非常重要 - 即使您的操作抛出异常,您也必须保证在操作后解锁等待线程。
- 如果您的后端分布在 多个 servers/JVMs.
中,它将无法工作
考虑以下方法:
public void upsert(int customerId, int somethingElse) {
// some code which is prone to race conditions
}
我想保护此方法免受竞争条件的影响,但这只有在具有相同 customerId
的两个线程同时调用它时才会发生。如果我使整个方法 synchronized
,它会降低效率并且它不是真正需要的。我真正想要的是围绕 customerId
同步它。 Java 是否有可能以某种方式实现?是否有任何内置工具,或者我需要 Map
of Integers
用作锁?
如果您认为我在这里做错了什么,也请随时提出建议:)
谢谢!
您正在寻找的概念称为分段锁定 或条带锁定。为每个客户单独配一把锁太浪费了(锁是相当重量级的)。相反,您希望将您的客户 ID 分区 space 分成合理数量的分区,以匹配所需的并行度。通常 8-16 就足够了,但这取决于方法所做的工作量。
这里概述了一个简单的方法:
private final Object[] locks = new Object[8];
synchronized (locks[customerId % locks.length]) {
...implementation...
}
private static final Set<Integer> lockedIds = new HashSet<>();
private void lock(Integer id) throws InterruptedException {
synchronized (lockedIds) {
while (!lockedIds.add(id)) {
lockedIds.wait();
}
}
}
private void unlock(Integer id) {
synchronized (lockedIds) {
lockedIds.remove(id);
lockedIds.notifyAll();
}
}
public void upsert(int customerId) throws InterruptedException {
try {
lock(customerId);
//Put your code here.
//For different ids it is executed in parallel.
//For equal ids it is executed synchronously.
} finally {
unlock(customerId);
}
}
- id 不仅可以是 'Integer',还可以是任何 class 并正确覆盖 'equals' 和 'hashCode' 方法。
- try-finally - 非常重要 - 即使您的操作抛出异常,您也必须保证在操作后解锁等待线程。
- 如果您的后端分布在 多个 servers/JVMs. 中,它将无法工作