com.liferay.portal.kernel.concurrent.CoalescedPipe Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of portal-service Show documentation
Show all versions of portal-service Show documentation
Contains interfaces for the portal services. Interfaces are only loaded by the global class loader and are shared by all plugins.
/**
* Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.concurrent;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Shuyang Zhou
*/
public class CoalescedPipe {
public CoalescedPipe() {
this(null);
}
public CoalescedPipe(Comparator comparator) {
_comparator = comparator;
_notEmptyCondition = _takeLock.newCondition();
_headElementLink = new ElementLink(null);
_lastElementLink = _headElementLink;
}
public long coalescedCount() {
return _coalescedCount.get();
}
public int pendingCount() {
return _pendingCount.get();
}
public void put(E e) throws InterruptedException {
if (e == null) {
throw new NullPointerException();
}
int pendingElements = -1;
_putLock.lockInterruptibly();
try {
if (_coalesceElement(e)) {
return;
}
_lastElementLink._nextElementLink = new ElementLink(e);
_lastElementLink = _lastElementLink._nextElementLink;
pendingElements = _pendingCount.getAndIncrement();
}
finally {
_putLock.unlock();
}
if (pendingElements == 0) {
_takeLock.lock();
try {
_notEmptyCondition.signal();
}
finally {
_takeLock.unlock();
}
}
}
public E take() throws InterruptedException {
E element = null;
_takeLock.lockInterruptibly();
try {
while (_pendingCount.get() == 0) {
_notEmptyCondition.await();
}
ElementLink garbageELementLink = _headElementLink;
_headElementLink = _headElementLink._nextElementLink;
garbageELementLink._nextElementLink = null;
element = _headElementLink._element;
_headElementLink._element = null;
int pendingElements = _pendingCount.getAndDecrement();
if (pendingElements > 1) {
_notEmptyCondition.signal();
}
}
finally {
_takeLock.unlock();
}
return element;
}
public Object[] takeSnapshot() {
_putLock.lock();
_takeLock.lock();
try {
Object[] pendingElements = new Object[_pendingCount.get()];
ElementLink currentElementLink =
_headElementLink._nextElementLink;
for (int i = 0; currentElementLink != null; i++) {
pendingElements[i] = currentElementLink._element;
currentElementLink = currentElementLink._nextElementLink;
}
return pendingElements;
}
finally {
_putLock.unlock();
_takeLock.unlock();
}
}
private boolean _coalesceElement(E e) {
try {
_takeLock.lockInterruptibly();
try {
ElementLink currentElementLink =
_headElementLink._nextElementLink;
if (_comparator != null) {
while (currentElementLink != null) {
if (_comparator.compare(
currentElementLink._element, e) == 0) {
_coalescedCount.incrementAndGet();
return true;
}
currentElementLink =
currentElementLink._nextElementLink;
}
}
else {
while (currentElementLink != null) {
if (currentElementLink._element.equals(e)) {
_coalescedCount.incrementAndGet();
return true;
}
currentElementLink =
currentElementLink._nextElementLink;
}
}
}
finally {
_takeLock.unlock();
}
}
catch (InterruptedException ie) {
// Continue to let the current element enter the pipe
}
return false;
}
private final AtomicLong _coalescedCount = new AtomicLong(0);
private final Comparator _comparator;
private ElementLink _headElementLink;
private ElementLink _lastElementLink;
private final Condition _notEmptyCondition;
private final AtomicInteger _pendingCount = new AtomicInteger(0);
private final ReentrantLock _putLock = new ReentrantLock();
private final ReentrantLock _takeLock = new ReentrantLock();
private static class ElementLink {
private ElementLink(E element) {
_element = element;
}
private E _element;
private ElementLink _nextElementLink;
}
}