在完成执行之前,@ Scheduled注释中使用的线程是否已发布到池中?

问题描述 投票:2回答:1

我有5个@Scheduled注释方法,我的ThreadPoolTask​​Scheduler的池大小是10.我的方法的注释是相同的,像这样。

@Scheduled(fixedDelay = 1000,initialDelay = 10000)

我的问题是;

当其中一个调度方法从池中获取一个线程并开始运行时;是否在执行完成之前将线程释放到池中? (例如在上下文切换等情况下)或者在执行结束之前使用该线程?

我的意思是,有可能计划任务的某些部分是使用thread-1完成的,而某些部分是使用thread-2完成的?

java spring scheduled-tasks java-threads spring-scheduled
1个回答
2
投票

线程是复杂的,我的理解并不像其他人那样伟大,但这是我尝试简要解释@Scheduled Spring注释的工作原理:

Spring使用TaskScheduler

public interface TaskScheduler {

    ScheduledFuture schedule(Runnable task, Trigger trigger);

    ScheduledFuture schedule(Runnable task, Date startTime);

    ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);

    ScheduledFuture scheduleAtFixedRate(Runnable task, long period);

    ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);

    ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);

}

https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/scheduling.html#scheduling-task-scheduler

它将带注释的代码(即任务代码)提交给称为执行程序的高级并发对象。执行者类是ThreadPoolTaskExecutor。该类将任务提交给线程池,以由池中的第一个可用线程运行。您设置的线程池大小决定了您可以拥有多少活动线程。如果将allowCoreThreadTimeOut设置为true,则池中的线程在其超时间隔内没有可用的工作将被终止。

Spring使用ThreadPoolTaskExecutor来管理线程池:

https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java

保持线程池活动可减少在等待创建线程时通常添加的时间。有关更多信息,请参阅此question

最终,java.lang.Thread类运行由ThreadPoolTaskExecutor创建的Runnable或Callable实例。 Thread类实现了一个run()方法,它基本上是您希望线程运行的代码:

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc) {
...

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/lang/Thread.java

线程之间的实际切换,即上下文切换is OS-dependent,但在一般线程中将在CPU之间进行划分,然后每个CPU根据超时间隔循环通过线程并执行一些工作,然后在线程之间连续暂停和切换,直到任务(s)完成。

是否在执行完成之前将线程释放到池中? (例如在上下文切换等情况下)或者在执行结束之前使用该线程?

Runnable代码肯定会在操作过程中停止执行,但线程池中的线程通常会保持活动状态,直到没有其他工作要做。

以下是Oracle documentation解释线程池的更多信息:

java.util.concurrent中的大多数执行程序实现都使用由工作线程组成的线程池。这种线程与它执行的Runnable和Callable任务分开存在,通常用于执行多个任务。

使用工作线程可以最大限度地减少由于线程创建而产生线程对象使用大量内存,而在大型应用程序中,分配和释放许多线程对象会产生大量的内存管理开销。

一种常见类型的线程池是固定线程池。这种类型的池始终具有指定数量的线程运行;如果某个线程在仍在使用时以某种方式终止,它将自动替换为新线程。任务通过内部队列提交到池中,只要有多个活动任务而不是线程,该队列就会保存额外的任务。

固定线程池的一个重要优点是使用它的应用程序可以优雅地降级。要理解这一点,请考虑一个Web服务器应用程序,其中每个HTTP请求都由一个单独的线程处理。如果应用程序只为每个新的HTTP请求创建一个新线程,并且系统接收的请求数超过它可以立即处理的数量,那么当所有这些线程的开销超过系统容量时,应用程序将突然停止响应所有请求。由于可以创建的线程数量有限制,应用程序不会像它们进入时那样快速地为HTTP请求提供服务,但它将在系统可以维持的时间内尽快为它们提供服务。

© www.soinside.com 2019 - 2024. All rights reserved.