All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fm.common.TaskRunner.scala Maven / Gradle / Ivy

/*
 * Copyright 2014 Frugal Mechanic (http://frugalmechanic.com)
 *
 * 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 fm.common

import java.util.concurrent.{ArrayBlockingQueue, BlockingQueue, LinkedBlockingQueue, SynchronousQueue}
import java.util.concurrent.{RejectedExecutionException, RejectedExecutionHandler, ThreadPoolExecutor, TimeUnit}

object TaskRunner extends Logging {
  val defaultThreads: Int = Runtime.getRuntime().availableProcessors()
  val defaultQueueSize: Int = Int.MinValue
  val defaultCoreThreads: Int = Int.MinValue
  val defaultMaxThreads: Int = Int.MinValue
  val defaultBlockOnFullQueue: Boolean = true

  def apply(
    name: String,
    threads: Int = defaultThreads,
    queueSize: Int = defaultQueueSize,
    coreThreads: Int = defaultCoreThreads,
    maxThreads: Int = defaultMaxThreads,
    blockOnFullQueue: Boolean = defaultBlockOnFullQueue
  ): TaskRunner = {
    val _coreThreads: Int = if (coreThreads == Int.MinValue) threads else coreThreads
    val _maxThreads:  Int = if (maxThreads == Int.MinValue) threads else maxThreads
    val _queueSize:   Int = if (queueSize == Int.MinValue) threads * 2 else queueSize
    new TaskRunner(name, _coreThreads, _maxThreads, _queueSize, blockOnFullQueue)
  }

  def newBuilder: TaskRunnerBuilder = new TaskRunnerBuilder
}

final class TaskRunner(val name: String, val coreThreads: Int, val maxThreads: Int, val queueSize: Int, val blockOnFullQueue: Boolean = true) extends TaskRunnerNonPriority(name) {
  
  private[this] val queue: BlockingQueue[Runnable] = {
    if (queueSize > 0) new ArrayBlockingQueue[Runnable](queueSize)
    else if (queueSize == 0) new SynchronousQueue[Runnable]()
    else new LinkedBlockingQueue[Runnable]()
  }
  
  private class BlockRejectExecutionHandler() extends RejectedExecutionHandler {
    def rejectedExecution(r: Runnable, executor: ThreadPoolExecutor): Unit = {
      // If the executor is shutting down then display a warning and drop the task
      if(executor.isShutdown) {
        shutdownWarning
        return
      }
      
      // Block on adding the task to the queue
      queue.put(r)
    }
  }
  
  private class StandardRejectExecutionHandler() extends RejectedExecutionHandler {
    def rejectedExecution(r: Runnable, executor: ThreadPoolExecutor): Unit = {
      // If the executor is shutting down then display a warning and drop the task
      if(executor.isShutdown) {
        shutdownWarning
        return
      }
      
      throw new RejectedExecutionException(s"$name - Queue is full")
    }
  }

  protected val executor: ThreadPoolExecutor = {
    val rejectedHandler: RejectedExecutionHandler = if (blockOnFullQueue) new BlockRejectExecutionHandler() else new StandardRejectExecutionHandler()
    val exec: ThreadPoolExecutor = new ThreadPoolExecutor(coreThreads, maxThreads, 60, TimeUnit.SECONDS, queue, TaskRunnerBase.newTaskRunnerThreadFactory(name), rejectedHandler)
    exec.allowCoreThreadTimeOut(true)
    exec
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy