@Scheduled批注中使用的线程在完成执行之前是否释放到池中?

时间:2019-03-27 15:28:04

标签: java spring scheduled-tasks java-threads spring-scheduled

我有5个@Scheduled注释的方法,我的ThreadPoolTask​​Scheduler的池大小为10。我的方法的注释相同且如此。

  

@Scheduled(fixedDelay = 1000,initialDelay = 10000)

我的问题是

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

我的意思是,计划任务的某些部分可能是由线程1完成的,而另一部分是由线程2完成的?

1 个答案:

答案 0 :(得分: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根据超时间隔在线程之间循环,并做一些工作,然后暂停并暂停。在线程之间连续切换,直到任务完成。

  

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

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

Oracle documentation的更多信息介绍了线程池:

  

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

     

使用工作线程可以最大程度地减少线程创建所带来的开销。   线程对象占用大量内存,并且在   大型应用程序,分配和取消分配多个线程   对象会产生大量的内存管理开销。

     

一种常见的线程池类型是固定线程池。这类   池始终有指定数量的正在运行的线程;如果一个线程是   在某种程度上终止使用时,它会自动   用新线程替换。任务通过   内部队列,每当有更多活动时,它就会容纳额外的任务   任务胜于线程。

     

固定线程池的一个重要优点是应用程序   使用它会降级。要了解这一点,请考虑使用Web服务器   每个HTTP请求由单独的线程处理的应用程序。   如果应用程序只是为每个新HTTP创建一个新线程   请求,系统收到的请求超出其处理能力   立即,应用程序将突然停止响应所有   当所有这些线程的开销超出最大容量时请求   系统。限制可以使用的线程数   创建后,该应用程序将无法处理HTTP请求,因为   它们一进入就很快,但是它将尽快为他们提供服务   系统可以维持。