【问题标题】:Java thread execution limited by count and timeJava 线程执行受计数和时间限制
【发布时间】:2019-07-14 07:30:20
【问题描述】:

我有 进程 的列表,我想像 每分钟十个进程那样执行它们。

我试过ExecutorServiceThreadPoolExecutorRateLimiter,但没有一个能支持我的情况,我也试过RxJava,但也许我不知道如何正确实现它。


示例

我有一个大小为 100KRunnable 列表,每个Runnable 都有这个逻辑:

  • rest api检索数据。
  • 对数据进行一些计算。
  • 将结果保存到数据库中。

所以我使用大小为 10ExecutorService 并在 Runnable#run() 内设置 延迟(5 秒) 来管理我需要的内容“每分钟十个进程",但仍然无法管理。

这个逻辑的要点是减少rest api上的请求。


更新

实际上,我们正在寻找的是有一个上限(在时间和操作数方面),而不是在各个操作之间平均分配时间,而不管它们各自的吞吐量如何。

即如果我有一个包含 100 个操作的列表,每个操作将花费 0.5 秒,并且我有一个速率限制器,而不是(分发后)确定单个操作应该花费 0.8 秒,那么我可以使用 0.3 秒的间隙来开始一个新的操作

【问题讨论】:

  • 每分钟正好十个进程是什么意思?
  • 我更新了我的问题。
  • 你能分享你的代码吗(在一个简单的例子中)?
  • 我有兴趣,RateLimiter 怎么解决不了这个问题? RateLimiter.create((double) 10 / (double) 60) 没有达到你想要的吗?你不需要runnables的均匀分布吗?
  • 实际上,我们正在寻找的是有一个上限(在时间和操作数方面),而不是在各个操作之间平均分配时间,而不管它们各自的吞吐量如何。即,如果我有一个包含 100 个操作的列表,每个操作需要 0.5 秒,并且我有一个速率限制器,而不是(分发后)确定单个操作应该花费 0.8 秒,那么我可以使用 0.3 秒的间隙来启动一个新的操作。

标签: java multithreading threadpool


【解决方案1】:

我可能会从 DelayQueue 提供我的线程池,以将自己限制为每分钟 10 个。

有关如何从 BlockingQueue 提供执行程序的示例,请参阅 https://stackoverflow.com/a/6306244/823393

【讨论】:

    【解决方案2】:

    你的意思是这样吗?产生一个线程的单个执行程序,该线程本身产生 10 个线程。

    private static final int numProcesses = 10;
    private static final ExecutorService executorService = Executors.newFixedThreadPool(numProcesses);
    
    public static void main(String[] args)
    {
        final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleAtFixedRate(Test::spawnTenThreads, 0, 5, TimeUnit.SECONDS);
    }
    
    private static void spawnTenThreads()
    {
        for (int i = 0; i < numProcesses; ++i)
        {
            final int iteration = i;
            executorService.submit(() -> System.out.println(iteration));
        }
    }
    

    【讨论】:

    • @MohamdAli 我的解决方案似乎对你有用,不是吗?
    【解决方案3】:

    我认为使用java.util.Timer 并在fixed rate 安排TimerTask 会获得最佳结果。

    假设您有一个TimerTask,它会在执行时打印出日期。

    public class PrintTimeAndIdTask extends TimerTask {
    
        private int id;
    
        public PrintTimeAndIdTask(int id) {
            this.id = id;
        }
    
        public void run() {
            System.out.println(new Date() + " : " + id);
        }
    }
    

    然后创建一个计时器并安排任务。每个都有不同的延迟,因此它们是 在您喜欢的时间间隔内平均分配。

    public static void main(String[] args) {
        Timer timer = new Timer();
    
        int taskCount = 10;
        int timeIntervalMs = 60000;
        int delayBetweenTasks = timeIntervalMs / taskCount;
    
    
        for (int i = 0; i < taskCount; i++) {
            TimerTask timerTask = new PrintTimeAndIdTask(taskCount);
    
            int taskDelay = (long) taskCount * delayBetweenTasks;
    
            timer.scheduleAtFixedRate(timerTask, taskDelay, timeIntervalMs);
        }
    }
    

    您会看到每 6 秒执行一次任务。

    Wed Feb 20 17:17:37 CET 2019 : 0
    Wed Feb 20 17:17:43 CET 2019 : 1
    Wed Feb 20 17:17:49 CET 2019 : 2
    Wed Feb 20 17:17:55 CET 2019 : 3
    Wed Feb 20 17:18:01 CET 2019 : 4
    Wed Feb 20 17:18:07 CET 2019 : 5
    Wed Feb 20 17:18:13 CET 2019 : 6
    Wed Feb 20 17:18:19 CET 2019 : 7
    Wed Feb 20 17:18:25 CET 2019 : 8
    Wed Feb 20 17:18:31 CET 2019 : 9
    Wed Feb 20 17:18:37 CET 2019 : 0
    Wed Feb 20 17:18:43 CET 2019 : 1
    Wed Feb 20 17:18:49 CET 2019 : 2
    Wed Feb 20 17:18:55 CET 2019 : 3
    ....
    

    请记住,Timer 默认情况下不会作为守护线程运行。如果您没有在应用程序关闭时明确取消它,它会继续运行,因此您的应用程序将不会关闭。

    【讨论】:

      猜你喜欢
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-23
      • 1970-01-01
      • 1970-01-01
      • 2013-01-17
      • 2010-10-18
      相关资源
      最近更新 更多