Java并发-如何在方法参数上同步
我有一个关于Java中的同步和并发的问题 所以我有一个方法,像这样:Java并发-如何在方法参数上同步,java,java-8,concurrency,parallel-processing,synchronization,Java,Java 8,Concurrency,Parallel Processing,Synchronization,我有一个关于Java中的同步和并发的问题 所以我有一个方法,像这样: private boolean loadData(final Integer fundId, List<Trade> trades) { synchronized (fundId) { // do lots of things here and finally load the trades into DB } } private boolean l
private boolean loadData(final Integer fundId, List<Trade> trades) {
synchronized (fundId) {
// do lots of things here and finally load the trades into DB
}
}
private boolean loadData(最终整数fundId,列表交易){
已同步(fundId){
//在这里做很多事情,最后将交易加载到DB中
}
}
在我进行此更改之前,完整的方法loadData
是同步的private synchronized boolean loadData
。然而,我的要求是,如果说fundId-1正在处理,那么我可以允许并发处理除1之外的任何其他fundId
因此,上面的代码也无法工作,因为锁将位于Integer对象上,因此不能同时处理其他fundId。
有没有一种方法可以实现基于方法参数的并发处理?编写的函数将在对象
fundId
上同步,而不是在整数上同步。因此,如果您使用相同的fundId
实例从另一个线程调用相同的函数,它将被阻塞。但是,如果与其他fundId
实例一起调用它,则无论其值如何,它都不会同步
如果需要基于某个值进行同步,可以使用一组共享的整数(即fundId)。在集合上同步,并尝试插入整数。如果它已经在那里,其他人正在处理该值,所以您等待。如果不存在,则插入、解锁、处理、再次锁定、删除值并发出信号。您需要在ConcurrentHashMap
中为fundId的每个值创建一个条目以锁定它
static Map<Integer, Object> locks = new ConcurrentHashMap<>();
private boolean loadData(final Integer fundId, List<Trade> trades){
locks.computeIfAbsent(fundId, k-> { /* your actual job */ return null; });
}
}
静态映射锁=新的ConcurrentHashMap();
私有布尔loadData(最终整数fundId,列表交易){
locks.computeIfAbsent(fundId,k->{/*您的实际作业*/return null;});
}
}
希望有帮助 您可以通过以下几种方式实现:
- 如果包含
loadData()
的类被称为FundLoader
,您可以拥有一个Map fundLoaders
,每个FundLoader负责加载给定fundId的交易。对于loadData
- 在loadData内执行自定义同步
更新-添加了fundsWaitingForLock,以防止已从fundLocks映射中获取锁的情况发生
private final Map fundLocks=new HashMap();
private final Map fundsWaitingForLock=新HashMap();
私有布尔loadData(最终整数fundId,最终列表交易){
对象锁;
同步(资金锁定){
lock=fundLocks.computeIfAbsent(fundId,id->new Object());
fundsWaitingForLock.computeIfAbsent(fundId,id->new AtomicInteger()).incrementAndGet();
}
已同步(锁定){
试一试{
//在这里做很多事情,最后将交易加载到DB中
返回true;
}最后{
同步(资金锁定){
if(fundsWaitingForLock.get(fundId.decrementAndGet()==0){
fundLocks.remove(fundId);
fundsWaitingForLock.remove(fundId);
}
}
}
}
}
- 传递一个锁而不是fundId
private boolean loadData(最终锁定fundIdLock,最终列表交易){
fundIdLock.lock();
试一试{
//在这里做很多事情,最后将交易加载到DB中
}最后{
fundIdLock.unlock();
}
返回true;
}
锁中的对象永远不会被删除,这可能会在长时间运行的过程中消耗整个内存。请查看我的评论。“一旦终止处理,不要忘记释放锁定的fundId”。释放锁意味着删除条目,因此内存中没有对象。感谢您的帮助,这与@k1r0的建议非常相似。我将试用它并在之后更新:-)再次感谢您的帮助。这与synchronized(fundId)
有何不同?它解决了什么问题?谢谢@Holger的评论。这确实非常有帮助,感谢M.Mas对答案的更新谢谢第一个和第二个想法似乎非常好。我可以试试。这与synchronized(fundId)
有何不同?它解决了什么问题?这与ConcurrentHashMap
变量受相同的竞争条件约束computeIfAbsent
将返回已经包含的对象(如果有),因此第一个线程的remove(fundId)
可以删除第二个线程(或任意数量的线程)已经在使用的对象。确实,我添加了一个等待锁定的线程数计数器,只有当它达到0时才执行删除。
private final Map<Integer, Object> fundLocks = new HashMap<>();
private final Map<Integer, AtomicInteger> fundsWaitingForLock = new HashMap<>();
private boolean loadData(final Integer fundId, final List<String> trades) {
Object lock;
synchronized (fundLocks) {
lock = fundLocks.computeIfAbsent(fundId, id -> new Object());
fundsWaitingForLock.computeIfAbsent(fundId, id -> new AtomicInteger()).incrementAndGet();
}
synchronized(lock) {
try {
// do lots of things here and finally load the trades into DB
return true;
} finally {
synchronized (fundLocks) {
if (fundsWaitingForLock.get(fundId).decrementAndGet() == 0) {
fundLocks.remove(fundId);
fundsWaitingForLock.remove(fundId);
}
}
}
}
}
private boolean loadData(final Lock fundIdLock, final List<String> trades) {
fundIdLock.lock();
try {
// do lots of things here and finally load the trades into DB
} finally {
fundIdLock.unlock();
}
return true;
}