Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java并发-如何在方法参数上同步_Java_Java 8_Concurrency_Parallel Processing_Synchronization - Fatal编程技术网

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

我有一个关于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 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;
}