Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.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 避免同时执行两次Spring@Async任务_Java_Spring_Multithreading_Asynchronous_Concurrency - Fatal编程技术网

Java 避免同时执行两次Spring@Async任务

Java 避免同时执行两次Spring@Async任务,java,spring,multithreading,asynchronous,concurrency,Java,Spring,Multithreading,Asynchronous,Concurrency,我只是在Spring框架中学习多线程,我不知道如何处理一个案例。我有一个持久的操作,我不想让用户等待它完成,我发现有一个@Async注释将该方法标记为异步可执行 我的问题是,阻止这种方法的最佳方式是什么,这样来自同一家公司的用户就不能在同一时间执行它。为了准确起见,我想阻止来自同一公司的用户同时执行分析数据(…)和分析统计(…) 我正在考虑使用ConcurrentHashMap,用户公司作为键,布尔值作为值,并在执行操作之前检查它。我想知道我的方向是否正确,或者Spring是否提供了其他更合适的

我只是在Spring框架中学习多线程,我不知道如何处理一个案例。我有一个持久的操作,我不想让用户等待它完成,我发现有一个@Async注释将该方法标记为异步可执行

我的问题是,阻止这种方法的最佳方式是什么,这样来自同一家公司的用户就不能在同一时间执行它。为了准确起见,我想阻止来自同一公司的用户同时执行分析数据(…)分析统计(…)

我正在考虑使用ConcurrentHashMap,用户公司作为键,布尔值作为值,并在执行操作之前检查它。我想知道我的方向是否正确,或者Spring是否提供了其他更合适的选择

@Service
public class LongOperationService {

   @Async
   public void analyzeData(User user, List<String> data) {
       boolean operationResult = performLongOperation(data);
       if (opeartionResult) {
           log.info("Long operation ended successfully")
       } else {
           log.error("Long operation failure")
       }
   }

   @Async
   public void analyzeStatistics(User user, List<String> statistics) {
       ...
   }

   private void performLongOperation(List<String> data) {
        // Just for demonstration
        Thread.sleep(10000);
        return true;
   }
}

public class User {
   String username;
   String company;
}
@服务
公共类长期运营服务{
@异步的
公共无效分析数据(用户、列表数据){
布尔运算结果=执行长运算(数据);
如果(操作结果){
log.info(“长时间操作成功结束”)
}否则{
日志错误(“长时间操作失败”)
}
}
@异步的
公共无效分析统计信息(用户、列表统计信息){
...
}
专用void performlong操作(列表数据){
//只是为了示范
睡眠(10000);
返回true;
}
}
公共类用户{
字符串用户名;
弦乐公司;
}

您可以使用
信号量来限制访问资源的线程数

由于您希望防止来自同一公司的用户同时访问您的analyze函数,因此应为每个公司创建信号量:

// Init on startup
// Key should be a unique identifier to a company, I assume the `String company` as key, you should adjust as your real requirement
static final Map<String, Semaphore> COMPANY_ENTRANT = new ConcurrentHashMap<>();
// for each company
COMPANY_ENTRANT.put(companyId, new Semaphore(1));

试着这样做:

private final Set<String> runningOperations = Collections.synchronizedSet(new HashSet<>());
private final Object lock = new Object();

@Async
public void analyzeData(User user, List<String> data) throws Exception {
    synchronized (lock) {
        if (runningOperations.contains(user.company))
            return;
        runningOperations.add(user.company);
    }
    try {
        boolean operationResult = performLongOperation(data);
        if (operationResult) {
            log.info("Long operation ended successfully");
        } else {
            log.error("Long operation failure");
        }
    } finally {
        runningOperations.remove(user.company);
    }
}
private final Set runningOperations=Collections.synchronizedSet(new HashSet());
私有最终对象锁=新对象();
@异步的
public void analyzeData(用户、列表数据)引发异常{
已同步(锁定){
if(runningOperations.contains(user.company))
返回;
runningOperations.add(user.company);
}
试一试{
布尔运算结果=执行长运算(数据);
if(操作结果){
log.info(“长时间操作成功结束”);
}否则{
日志错误(“长时间操作失败”);
}
}最后{
runningOperations.remove(user.company);
}
}

应该看到来自同一公司的用户的结果是什么?相同的结果或第二个用户在运行操作时必须失败?我想简化任务,忽略返回值的事实,这样我得到的任何输出都会记录在消息中。第一个用户正在启动
布尔运算结果=执行长运算(数据)
和另一个事件不应启动该操作,因为第一个事件已启动该操作。具有同步块的解决方案可能是可接受的,但这是不可接受的。“Check和add不是原子的。”我想这么小的概率就足够了。现在好了吗?
COMPANY\u ENTRANT.putIfAbsent
将返回
null
,如果之前map中没有值
COMPANY\u ENTRANT.computeIfAbsent(user.getCompany(),c->new Semaphore(1))
在您的情况下,来自同一公司的两个用户将一个接一个地运行操作
 Semaphore entrant = COMPANY_ENTRANT.putIfAbsent(user.getCompany(), new Semaphore(1));
private final Set<String> runningOperations = Collections.synchronizedSet(new HashSet<>());
private final Object lock = new Object();

@Async
public void analyzeData(User user, List<String> data) throws Exception {
    synchronized (lock) {
        if (runningOperations.contains(user.company))
            return;
        runningOperations.add(user.company);
    }
    try {
        boolean operationResult = performLongOperation(data);
        if (operationResult) {
            log.info("Long operation ended successfully");
        } else {
            log.error("Long operation failure");
        }
    } finally {
        runningOperations.remove(user.company);
    }
}