我有一个有8个线程的线程池

private static final ExecutorService SERVICE = Executors.newFixedThreadPool(8);

我的机制模拟100个用户(100个任务)的工作:

List<Callable<Boolean>> callableTasks = new ArrayList<>();
for (int i = 0; i < 100; i++) { // Number of users == 100
    callableTasks.add(new Task(client));
}
SERVICE.invokeAll(callableTasks);
SERVICE.shutdown();

用户执行生成文档的任务.

  1. 获取任务的UUID;
  2. 每10秒获取一次任务状态;
  3. 如果任务已准备就绪,请获取文档.
public class Task implements Callable<Boolean> {

    private final ReportClient client;

    public Task(ReportClient client) {
        this.client = client;
    }

    @Override
    public Boolean call() {
        final var uuid = client.createDocument(documentId);
        GetStatusResponse status = null;
        do {
            try {
                Thread.sleep(10000); // This stop current thread, but not a Task!!!!
            } catch (InterruptedException e) {
                return Boolean.FALSE;
            }
            status = client.getStatus(uuid);
        } while (Status.PENDING.equals(status.status()));
        final var document = client.getReport(uuid);
        return Boolean.TRUE;
    }
}

我想给另一个任务留出空闲时间(10秒).但是,当调用命令Thread.sleep(10000);时,当前线程将暂停其执行.前8个任务暂停,92个任务等待10秒.如何同时完成Thread.sleep(10000);项正在进行的任务?

推荐答案

编辑:我刚刚发布了这个答案,并意识到您似乎在使用该代码模拟真实用户与某个系统的交互.我强烈建议只使用一个负载测试实用程序,而不是try 自己的.然而,在这种情况下,只使用CachedThreadPool就可以做到这一点,尽管这可能不是一个非常健壮或可伸缩的解决方案.

线这里的sleep()行为按预期工作:它挂起线程,让CPU执行其他线程.

因此,您需要两件相互排斥的事情:一方面,如果文档还没有准备好,线程应该可以自由地执行其他操作,但应该以某种方式返回并在10秒内再次判断文档的状态.

这意味着您必须 Select :

  • 您肯定需要对每个文档进行每10秒一次的判断—在这种情况下,可以使用cachedThreadPool并让它生成所需的尽可能多的线程,但请记住,您将承担大量线程的开销,而这些线程实际上什么都不做.

  • 或者,您可以首先启动异步文档创建过程,然后只判断可调用项中的状态,并根据需要重试.

类似于:

public class Task implements Callable<Boolean> {
    private final ReportClient client;
    private final UUID uuid;
    // all args constructor omitted for brevity
    @Override
    public Boolean call() {
        GetStatusResponse status = client.getStatus(uuid);
        if (Status.PENDING.equals(status.status())) {
            final var document = client.getReport(uuid);
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE; //retry next time
        }
    }
}

List<Callable<Boolean>> callableTasks = new ArrayList<>();
for (int i = 0; i < 100; i++) { 
    var uuid = client.createDocument(documentId); //not sure where documentId comes from here in your code
    callableTasks.add(new Task(client, uuid));
}

List<Future<Boolean>> results = SERVICE.invokeAll(callableTasks); 
// retry logic until all results come back as `true` here

这假设createDocument是相对有效的,但该阶段也可以并行化,您只需要使用Runnable个任务的单独列表,并使用executor服务调用它们.

Java相关问答推荐

Annotation @ Memphier无法正常工作,并表示:class需要一个bean,但找到了2个bean:

调用引发泛型异常的泛型方法时出现编译错误

FALSE:它应该在什么时候使用?

如何创建一个2d自上而下的移动系统,其中移动,同时持有两个关键是可能的处理?

Java中的死锁及其重入锁和锁

为什么使用JDK21获取锁定锁比使用JDK11慢

为什么在maven中,getLast方法不适用于List?

将java.util.Date转换为OffsetDateTime

我如何知道MediaDiscoverer何时完成发现介质?

如何对多个字段进行分组和排序?

使SLF4J在Android中登录到Logcat,在测试中登录到控制台(Gradle依赖问题)

try 将JSON字符串响应从API转换为映射字符串、对象>;时出错

FETCH类型设置为LAZY,但它仍会发送第二个请求

在使用具有不同成本的谓词调用allMatch之前对Java流进行排序会带来什么好处吗?

在Oracle db中,当我们提供字符串而不是数字时,比较是如何工作的?

具有最大共同前景像素的图像平移优化算法

Java编译器是否进行了持续的折叠优化,以及如何进行判断?

@此处不能应用可为null的批注

在外部类和内部类之间,当调用外部类内部或外部的主方法时,它们的静态初始化程序的运行顺序不同

Java 中的 IS 关系