有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java@Async阻止一个线程继续,直到其他线程完成

我有一个应用程序,需要计算一定次数的东西。这个计算函数有注释@Async(来自Spring框架),可以在4个线程上运行这些计算。问题是我需要大约40000次这样的计算,我想知道所有计算的开始和结束之间的时间,所以我知道调用计算函数的for循环之前和之后的时间。但是现在所有的计算都放在一个队列中,因此for循环立即完成,时间大约为1秒,而计算需要几个小时才能完成。我曾尝试将最大队列大小设置为大约100(这对减少内存使用也很好),但这也不是解决方案,因为我将在总时间内错过最后100次计算。有没有办法在for循环之后暂停正在执行的代码,直到所有线程都完成了它们的工作,但仍然能够使用@Async注释

以下代码说明了同样的问题:

执行类:

public class Foo {
    public void executeBlaALotOfTimes() {
        long before = System.currentTimeMillis();

        for (int i = 0; i<40000; i++) {
            executeBla();
        }

        long after = System.currentTimeMillis(); 

        System.out.println("Time it took for a lot of bla to execute: " + (after - before) / 1000.0 + " seconds.");
    }
}

以及执行计算的类:

@Service
public class Bar {
    @Async
    public void executeBla() {
        System.out.println("Bla!");
    }
}

这将导致以下输出(假设Foo中的代码执行速度无限快):

Time it took for a lot of bla to execute: 0.0 seconds.
Bla!
Bla!
Bla!
Bla!
.
.
.
etc

共 (1) 个答案

  1. # 1 楼答案

    如果需要等待执行完成,则可以返回Future作为返回值,例如

    @Async
    public Future<Void> executeBla() {
        System.out.println("Bla!");
        return new AsyncResult<Void>(null);
    }
    

    这有点人为,因为没有返回实际值,但仍允许调用代码等待所有执行完成:

    public void executeBlaALotOfTimes() {
        long before = System.currentTimeMillis();
    
        Collection<Future<Void>> futures = new ArrayList<Future<Void>>();
    
        for (int i = 0; i<40000; i++) {
            futures.add(executeBla());
        }
    
        for (Future<Void> future : futures) {
            future.get();
        }
    
        long after = System.currentTimeMillis(); 
    
        System.out.println("Time it took for a lot of bla to execute: " + (after - before) / 1000.0 + " seconds.");
    }
    

    这里,第一个循环触发异步任务,并将未来存储在一个列表中。然后,秒循环迭代未来,等待每一个循环完成