Package org.springframework.batch.admin.util

Source Code of org.springframework.batch.admin.util.ThrottledTaskExecutor

/*
* Copyright 2009-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.admin.util;

import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.TaskRejectedException;

import java.util.concurrent.FutureTask;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

/**
* <p>
* A {@link TaskExecutor} with a throttle limit which works by delegating to an
* existing task executor and limiting the number of tasks submitted.
* </p>
* <p>
* A throttle limit is provided to limit the number of pending requests over and
* above the features provided by the other task executors. The submit method
* blocks until there are results available to retrieve. This limit is different
* (and orthogonal) to any queue size imposed by the delegate
* {@link TaskExecutor}: such queues normally do not throttle, in the sense that
* they always accept more work, until they fill up, at which point they reject.
* The point of a throttle is to not reject any work, but to still limit the
* number of concurrent tasks.
* </p>
* @author Dave Syer
*
*/
public class ThrottledTaskExecutor implements TaskExecutor {

  private Semaphore semaphore;

  private volatile AtomicInteger count = new AtomicInteger(0);

  private TaskExecutor taskExecutor = new SyncTaskExecutor();

  /**
   * Create a {@link ThrottledTaskExecutor} with infinite
   * (Integer.MAX_VALUE) throttle limit. A task can always be submitted.
   */
  public ThrottledTaskExecutor() {
    this(null, Integer.MAX_VALUE);
  }

  /**
   * Create a {@link ThrottledTaskExecutor} with infinite
   * (Integer.MAX_VALUE) throttle limit. A task can always be submitted.
   *
   * @param taskExecutor the {@link TaskExecutor} to use
   */
  public ThrottledTaskExecutor(TaskExecutor taskExecutor) {
    this(taskExecutor, Integer.MAX_VALUE);
  }

  /**
   * Create a {@link ThrottledTaskExecutor} with finite throttle
   * limit. The submit method will block when this limit is reached until one
   * of the tasks has finished.
   *
   * @param taskExecutor the {@link TaskExecutor} to use
   * @param throttleLimit the throttle limit
   */
  public ThrottledTaskExecutor(TaskExecutor taskExecutor, int throttleLimit) {
    super();
    if (taskExecutor != null) {
      this.taskExecutor = taskExecutor;
    }
    this.semaphore = new Semaphore(throttleLimit);
  }

  /**
   * Limits the number of concurrent executions on the enclosed task executor.
   * Do not call this after initialization (for configuration purposes only).
   *
   * @param throttleLimit the throttle limit to apply
   */
  public void setThrottleLimit(int throttleLimit) {
    this.semaphore = new Semaphore(throttleLimit);
  }

  /**
   * Public setter for the {@link TaskExecutor} to be used to execute the
   * tasks submitted. The default is synchronous, executing tasks on the
   * calling thread. In this case the throttle limit is irrelevant as there
   * will always be at most one task pending.
   *
   * @param taskExecutor {@link org.springframework.core.task.TaskExecutor}
   */
  public void setTaskExecutor(TaskExecutor taskExecutor) {
    this.taskExecutor = taskExecutor;
  }

  /**
   * Submit a task for execution by the delegate task executor, blocking if
   * the throttleLimit is exceeded.
   *
   * @see TaskExecutor#execute(Runnable)
   */
  public void execute(Runnable task) {
    if (task == null) {
      throw new NullPointerException("Task is null in ThrottledTaskExecutor.");
    }
    doSubmit(task);
  }

  /**
   * Get an estimate of the number of pending requests.
   *
   * @return the estimate
   */
  public int size() {
    return count.get();
  }

  private Runnable doSubmit(final Runnable task) {

    try {
      semaphore.acquire();
      count.incrementAndGet();
    }
    catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new TaskRejectedException("Task could not be submitted because of a thread interruption.");
    }

    try {
      taskExecutor.execute(new FutureTask<Object>(task, null) {
        @Override
        protected void done() {
          semaphore.release();
          count.decrementAndGet();
        }
      });
    }
    catch (TaskRejectedException e) {
      semaphore.release();
      count.decrementAndGet();
      throw e;
    }

    return task;
  }
}
TOP

Related Classes of org.springframework.batch.admin.util.ThrottledTaskExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.