/* * Copyright 2017 LinkedIn, Inc * * 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.linkedin.parseq.internal; import java.util.concurrent.ConcurrentLinkedDeque; import com.linkedin.parseq.Priority; import com.linkedin.parseq.internal.SerialExecutor.TaskQueue; /** * {@link TaskQueue} implementation that recognizes only two classes of priorities: * <ul> * <li>greater than {@link Priority#DEFAULT_PRIORITY}</li> * <li>less or equal to {@link Priority#DEFAULT_PRIORITY}</li> * </ul> * Elements from first class are polled in FIFO order while elements from second class are polled * in LIFO order. The rationale behind it is that elements with highest priorities will be mostly * timeouts and we want to minimize variance in difference between time at which they were supposed * to run and time they actually run. We poll default and lower priority elements using LIFO in order * to improve memory cache locality: tasks scheduled most recently for execution are most likely to still * be in cache. * <p> * It is a faster implementation of {@link TaskQueue} than {@link FIFOPriorityQueue} * that can be used when tasks do not use priorities in general. * <p> * This queue supports two classes of priorities because {@code Priority.MAX_PRIORITY} * is used by timeouts. * * @author Jaroslaw Odzga (jodzga@linkedin.com) * */ public class LIFOBiPriorityQueue<T extends Prioritizable> implements SerialExecutor.TaskQueue<T> { private final ConcurrentLinkedDeque<T> _highPriority = new ConcurrentLinkedDeque<>(); private final ConcurrentLinkedDeque<T> _lowPriority = new ConcurrentLinkedDeque<>(); public void add(T value) { if (value.getPriority() > Priority.DEFAULT_PRIORITY) { _highPriority.addLast(value); } else { _lowPriority.addFirst(value); } } public T poll() { T highPriority = _highPriority.pollFirst(); return (highPriority != null) ? highPriority : _lowPriority.pollFirst(); } }