Spring - 添加低优先级多线程服务(对生产性能没有影响)

我们有一个 Spring 应用程序,我想添加一个服务,该服务将使用多个线程处理 10Ks ID,但将作为后台进程而不影响生产实时性

服务将更新数据库并发送外部提供商请求。

我不希望服务影响生产性能/计时,我想以低优先级对每个 ID 执行操作

我希望对超出此特定执行器范围的所有其他线程设置低优先级。

答案使用ThreadPoolExecutor与我的案例更相关吗?

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, numOfWorkerThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

threadPool.setThreadFactory(new OpJobThreadFactory(Thread.NORM_PRIORITY-2));


public final static class OpJobThreadFactory implements ThreadFactory {

 private int priority;

 public OpJobThreadFactory(int priority) {

  this(priority, true);

}


@Override

public Thread newThread(Runnable r) {

  Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());

  t.setDaemon(daemon);

  t.setPriority(priority);

 }

}

  • 也许甚至使用Thread.MIN_PRIORITY

或者我可以使用Executors.newCachedThreadPool()

创建一个线程池,该线程池根据需要创建新线程,但会重用以前构造的线程(当它们可用时)。这些池通常会提高执行许多短期异步任务的程序的性能

我还应该使用Spring bean吗?因为我需要按需/请求创建池,所以似乎不需要/错误

编辑 我应该使用Spring Actuator来获取此任务还是其他监控工具?

Spring Boot Actuator 模块通过提供健康检查、审计、指标收集、HTTP 跟踪等生产就绪功能来帮助您监控和管理 Spring Boot 应用程序。所有这些功能都可以通过 JMX 或 HTTP 端点访问。


holdtom
浏览 146回答 2
2回答

达令说

我想澄清一下这个问题什么是线程优先级?根据 java SE 文档每个线程都有一个优先级。具有较高优先级的线程优先于具有较低优先级的线程执行。即使您创建具有优先级的线程,它也不能完全保证优先级较低的线程首先执行,您可能必须阻塞优先级较低的线程,直到执行其他线程对于小型 java 程序,您可以自己处理线程执行,但对于较大的程序,建议您使用 vanilla Java 中的 Executor Framework(来自 java.util.concurrent 包)或使用 spring TaskExecutor。通过使用这两个框架,您可以异步执行任务,即作为主任务的一部分在后台执行它们。对生产的影响:例如,主要任务将是调用您的其余端点(即/account),并在调用帐户端点时您想要向客户发送欢迎电子邮件,这是第三方 API 调用,可以使用 Executor Framework 或 Spring 异步执行TaskExecutor 异步执行它们,即作为后台进程,它们不会对当前 API 产生影响,但肯定会对生产服务器产生影响,因为您在同一个 JVM 中运行线程并且它们共享公共内存。如果创建了许多线程但没有销毁,那么服务器肯定会崩溃。因此,使用 Executor Framework 或 Spring TaskExecutor 并不能保证它不会影响您当前的生产,它肯定会提高所调用的其余 API 的性能。因为它是异步执行的并且关于您的其他问题我可以使用 Executors.newCachedThreadPool()是的,如果您有许多短期任务,例如更新数据库中的单个列或仅触发一次休息端点,并且它不适合批量加载或执行某些更新 10000 条记录的后端作业,因为它会创建更大的数量每个任务都有多个线程,您肯定会遇到内存问题。

慕莱坞森

这是一种创建可配置任务“堆”并始终将主任务保留在堆顶部的方法。总结这个过程,您应该创建一个自定义任务执行器。首先,您需要创建一个 ThreadPoolTaskExecutor bean,并覆盖一个方法。需要修改的属性有:CorePoolSize(初始线程数)、QueueCapacity(队列中等待的线程数)和MaxPoolSize(最大线程数)。使用这些参数,您可以配置应用程序限制,以使该服务不会影响生产性能。 @Bean("CustomTaskExecutor")  public TaskExecutor threadPoolTaskExecutor(          @Value("${spring.async.core-pool-size}") int corePoolSize,          @Value("${spring.async.max-pool-size}") int maxPoolSize,          @Value("${spring.async.queue-capacity}") int queueCapacity) {    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() {      @Override      protected BlockingQueue<Runnable> createQueue(int queueCapacity) {        return new PriorityBlockingQueue<Runnable>(queueCapacity);      }    };    executor.setCorePoolSize(corePoolSize);    executor.setMaxPoolSize(maxPoolSize);    executor.setQueueCapacity(queueCapacity);    return executor;  }之后,您需要制定任务执行者可以理解的优先级。为此,我们需要创建两个类: 1) 一个实现 Runnable 接口的自定义类,该类将运行任务 2) 一个扩展 FutureTask 并实现 Comparable 接口的包装类,以便任务执行器可以理解任务的优先级选择逻辑任务public class Task implements Runnable {    private Consumer<Job> jobConsumer;    private Job job;      public Job getJob() {        return this.job;      }      public Task(Consumer<Job> jobConsumer, Job job) {        this.jobConsumer = jobConsumer;        this.job = job;      }      @Override      public void run() {        this.jobConsumer.accept(job);      }    }然后你就有了 FutureCustomTask 类:public class FutureCustomTask extends FutureTask<FutureCustomTask> implements Comparable<FutureCustomTask> {private Task task;public FutureCustomTask(Task task) {    super(task, null);    this.task = task;  }@Override  public int compareTo(FutureCustomTask o) {    return task.getJob().getPriority().compareTo(o.task.getJob().getPriority());  }}为了执行任务执行器需要自动装配。然后,您可以创建 Task 对象,将其包装在 FutureCustomTask 中,并将其传递给 TaskExecutor。代码应如下所示:@Autowiredprivate TaskExecutor taskExecutor;@Autowiredprivate JobBusiness jobBusiness;...Task task = new Task(jobBusiness::performSomethingOn, job);taskExecutor.execute(new FutureCustomTask(task));
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java