Java: 基于对象值同步
Java: Synchronization based on object value
我想根据输入参数同步一个方法或一个块。
所以我有一个 API,它在 post 有效负载中有两个 long 类型(可以是原始类型或包装器)的输入(比如 id1 和 id2),可以是 JSON.这个API会被多个线程随机同时或不同时间调用
现在如果第一个 API 调用有 id1=1 和 id2=1,同时另一个 API 调用有 id1=1 和 id2=1,它应该等待第一个 API 调用在执行第二个调用之前完成处理。如果第二个 API 调用具有不同的值组合,如 id1=1 和 id2=2,它应该并行进行,没有任何等待时间。
我不介意创建 API 资源方法也可以调用的服务方法,而不是直接在 API 资源方法中处理。
我正在使用 Spring boot Rest Controlller APIs.
**编辑**
我已经尝试按照建议使用地图,但这部分有效。它等待所有输入值,而不仅仅是相同的输入值。下面是我的代码:
public static void main(String[] args) throws Exception {
ApplicationContext context = SpringApplication.run(Application.class, args);
AccountResource ar = context.getBean(AccountResource.class);
UID uid1 = new UID();
uid1.setFieldId(1);
uid1.setLetterFieldId(1);
UID uid2 = new UID();
uid2.setFieldId(2);
uid2.setLetterFieldId(2);
UID uid3 = new UID();
uid3.setFieldId(1);
uid3.setLetterFieldId(1);
Runnable r1 = new Runnable() {
@Override
public void run() {
while (true) {
ar.test(uid1);
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
while (true) {
ar.test(uid2);
}
}
};
Runnable r3 = new Runnable() {
@Override
public void run() {
while (true) {
ar.test(uid3);
}
}
};
Thread t1 = new Thread(r1);
t1.start();
Thread t2 = new Thread(r2);
t2.start();
Thread t3 = new Thread(r3);
t3.start();
}
@Path("v1/account")
@Service
public class AccountResource {
public void test(UID uid) {
uidFieldValidator.setUid(uid);
Object lock;
synchronized (map) {
lock = map.get(uid);
if (lock == null) {
map.put(uid, (lock = new Object()));
}
synchronized (lock) {
//some operation
}
}
}
}
package com.urman.hibernate.test;
import java.util.Objects;
public class UID {
private long letterFieldId;
private long fieldId;
private String value;
public long getLetterFieldId() {
return letterFieldId;
}
public void setLetterFieldId(long letterFieldId) {
this.letterFieldId = letterFieldId;
}
public long getFieldId() {
return fieldId;
}
public void setFieldId(long fieldId) {
this.fieldId = fieldId;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
return Objects.hash(fieldId, letterFieldId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
UID other = (UID) obj;
return fieldId == other.fieldId && letterFieldId == other.letterFieldId;
}
}
您需要一组锁,您可以将其保存在地图中并根据需要进行分配。这里我假设你的 id1 和 id2 是字符串;酌情调整。
Map<String,Object> lockMap = new HashMap<>();
:
void someMethod(String id1, String id2) {
Object lock;
synchronized (lockMap) {
lock = lockMap.get(id1+id2);
if (lock == null) lockMap.put(id1+id2, (lock = new Object()));
}
synchronized (lock) {
:
}
}
地图操作需要一点点 'global' 同步,或者您可以使用其中一种并发实现。为了简化实现,我使用了基础 HashMap。
选择锁后,对其进行同步。
我想根据输入参数同步一个方法或一个块。
所以我有一个 API,它在 post 有效负载中有两个 long 类型(可以是原始类型或包装器)的输入(比如 id1 和 id2),可以是 JSON.这个API会被多个线程随机同时或不同时间调用
现在如果第一个 API 调用有 id1=1 和 id2=1,同时另一个 API 调用有 id1=1 和 id2=1,它应该等待第一个 API 调用在执行第二个调用之前完成处理。如果第二个 API 调用具有不同的值组合,如 id1=1 和 id2=2,它应该并行进行,没有任何等待时间。
我不介意创建 API 资源方法也可以调用的服务方法,而不是直接在 API 资源方法中处理。
我正在使用 Spring boot Rest Controlller APIs.
**编辑** 我已经尝试按照建议使用地图,但这部分有效。它等待所有输入值,而不仅仅是相同的输入值。下面是我的代码:public static void main(String[] args) throws Exception {
ApplicationContext context = SpringApplication.run(Application.class, args);
AccountResource ar = context.getBean(AccountResource.class);
UID uid1 = new UID();
uid1.setFieldId(1);
uid1.setLetterFieldId(1);
UID uid2 = new UID();
uid2.setFieldId(2);
uid2.setLetterFieldId(2);
UID uid3 = new UID();
uid3.setFieldId(1);
uid3.setLetterFieldId(1);
Runnable r1 = new Runnable() {
@Override
public void run() {
while (true) {
ar.test(uid1);
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
while (true) {
ar.test(uid2);
}
}
};
Runnable r3 = new Runnable() {
@Override
public void run() {
while (true) {
ar.test(uid3);
}
}
};
Thread t1 = new Thread(r1);
t1.start();
Thread t2 = new Thread(r2);
t2.start();
Thread t3 = new Thread(r3);
t3.start();
}
@Path("v1/account")
@Service
public class AccountResource {
public void test(UID uid) {
uidFieldValidator.setUid(uid);
Object lock;
synchronized (map) {
lock = map.get(uid);
if (lock == null) {
map.put(uid, (lock = new Object()));
}
synchronized (lock) {
//some operation
}
}
}
}
package com.urman.hibernate.test;
import java.util.Objects;
public class UID {
private long letterFieldId;
private long fieldId;
private String value;
public long getLetterFieldId() {
return letterFieldId;
}
public void setLetterFieldId(long letterFieldId) {
this.letterFieldId = letterFieldId;
}
public long getFieldId() {
return fieldId;
}
public void setFieldId(long fieldId) {
this.fieldId = fieldId;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
return Objects.hash(fieldId, letterFieldId);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
UID other = (UID) obj;
return fieldId == other.fieldId && letterFieldId == other.letterFieldId;
}
}
您需要一组锁,您可以将其保存在地图中并根据需要进行分配。这里我假设你的 id1 和 id2 是字符串;酌情调整。
Map<String,Object> lockMap = new HashMap<>();
:
void someMethod(String id1, String id2) {
Object lock;
synchronized (lockMap) {
lock = lockMap.get(id1+id2);
if (lock == null) lockMap.put(id1+id2, (lock = new Object()));
}
synchronized (lock) {
:
}
}
地图操作需要一点点 'global' 同步,或者您可以使用其中一种并发实现。为了简化实现,我使用了基础 HashMap。
选择锁后,对其进行同步。