com.phloc.commons.concurrent.collector.ConcurrentCollectorMultiple Maven / Gradle / Ivy
/**
* Copyright (C) 2006-2014 phloc systems
* http://www.phloc.com
* office[at]phloc[dot]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 com.phloc.commons.concurrent.collector;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.callback.IThrowingRunnableWithParameter;
import com.phloc.commons.lang.GenericReflection;
/**
* Concurrent collector that performs action on multiple objects at once
*
* @author Philip Helger
* @param
* The type of the objects in the queue.
*/
public class ConcurrentCollectorMultiple extends AbstractConcurrentCollector
{
/** The default number of objects to be put in the queue for execution. */
public static final int DEFAULT_MAX_PERFORM_COUNT = DEFAULT_MAX_QUEUE_SIZE / 2;
private static final Logger s_aLogger = LoggerFactory.getLogger (ConcurrentCollectorMultiple.class);
@Nonnegative
private final int m_nMaxPerformCount;
private IThrowingRunnableWithParameter > m_aPerformer;
/**
* Constructor that uses {@link #DEFAULT_MAX_QUEUE_SIZE} elements as the
* maximum queue length.
*/
public ConcurrentCollectorMultiple ()
{
this (null);
}
/**
* Constructor that uses {@link #DEFAULT_MAX_QUEUE_SIZE} elements as the
* maximum queue length and {@link #DEFAULT_MAX_PERFORM_COUNT} as the max
* perform count.
*
* @param aPerformer
* The callback to be invoked everytime objects are collected. May be
* null
but in that case
* {@link #setPerformer(IThrowingRunnableWithParameter)} must be
* invoked!
*/
public ConcurrentCollectorMultiple (@Nullable final IThrowingRunnableWithParameter > aPerformer)
{
this (DEFAULT_MAX_QUEUE_SIZE, DEFAULT_MAX_PERFORM_COUNT, aPerformer);
}
/**
* Constructor.
*
* @param nMaxQueueSize
* The maximum number of items that can be in the queue. Must be >
* 0.
* @param nMaxPerformCount
* The maximum number of objects to be put in the queue for execution.
* @param aPerformer
* The callback to be invoked everytime objects are collected. May be
* null
but in that case
* {@link #setPerformer(IThrowingRunnableWithParameter)} must be
* invoked!
*/
public ConcurrentCollectorMultiple (@Nonnegative final int nMaxQueueSize,
@Nonnegative final int nMaxPerformCount,
@Nullable final IThrowingRunnableWithParameter > aPerformer)
{
super (nMaxQueueSize);
if (nMaxPerformCount > nMaxQueueSize || nMaxPerformCount < 1)
throw new IllegalArgumentException ("max perform size is illegal: " + nMaxPerformCount);
m_nMaxPerformCount = nMaxPerformCount;
if (aPerformer != null)
setPerformer (aPerformer);
}
protected final void setPerformer (@Nonnull final IThrowingRunnableWithParameter > aPerformer)
{
m_aPerformer = ValueEnforcer.notNull (aPerformer, "Performer");
}
private void _executeCallback (@Nonnull final List aObjectsToPerform)
{
if (!aObjectsToPerform.isEmpty ())
{
try
{
// Perform the action on the objects, regardless of whether a
// "stop queue message" was received or not
m_aPerformer.run (aObjectsToPerform);
}
catch (final Throwable t)
{
s_aLogger.error ("Failed to perform actions on " +
aObjectsToPerform.size () +
" objects - objects have been lost!", t);
}
// clear perform list after execution
aObjectsToPerform.clear ();
}
}
public final void run ()
{
if (m_aPerformer == null)
throw new IllegalStateException ("No performer set!");
try
{
// The temporary list that contains all objects to be delivered
final List aObjectsToPerform = new ArrayList ();
boolean bQueueIsStopped = false;
while (true)
{
// Block until the first object is in the queue
Object aCurrentObject = m_aQueue.take ();
if (aCurrentObject == STOP_QUEUE_OBJECT)
break;
// add current object
aObjectsToPerform.add (GenericReflection.